001/* 002 * Copyright 2020 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.cms.contenttype; 017 018import java.util.ArrayList; 019import java.util.List; 020import java.util.Optional; 021 022import org.apache.avalon.framework.component.Component; 023import org.apache.avalon.framework.configuration.Configuration; 024import org.apache.avalon.framework.configuration.ConfigurationException; 025import org.apache.avalon.framework.context.Context; 026import org.apache.avalon.framework.context.ContextException; 027import org.apache.avalon.framework.context.Contextualizable; 028import org.apache.avalon.framework.logger.AbstractLogEnabled; 029import org.apache.avalon.framework.service.ServiceException; 030import org.apache.avalon.framework.service.ServiceManager; 031import org.apache.avalon.framework.service.Serviceable; 032import org.apache.cocoon.components.LifecycleHelper; 033import org.apache.commons.lang3.StringUtils; 034 035import org.ametys.cms.contenttype.ContentTypesHelper.ViewConfigurationsByType; 036import org.ametys.runtime.i18n.I18nizableText; 037import org.ametys.runtime.model.ModelHelper.ConfigurationAndPluginName; 038import org.ametys.runtime.model.View; 039import org.ametys.runtime.model.ViewParser; 040 041/** 042 * Helper for content types parsing 043 */ 044public class ContentTypesParserHelper extends AbstractLogEnabled implements Component, Serviceable, Contextualizable 045{ 046 /** The Avalon role */ 047 public static final String ROLE = ContentTypesParserHelper.class.getName(); 048 049 /** The content types helper */ 050 protected ContentTypesHelper _contentTypesHelper; 051 052 private Context _context; 053 private ServiceManager _manager; 054 055 056 public void contextualize(Context context) throws ContextException 057 { 058 _context = context; 059 } 060 061 @Override 062 public void service(ServiceManager manager) throws ServiceException 063 { 064 _manager = manager; 065 _contentTypesHelper = (ContentTypesHelper) _manager.lookup(ContentTypesHelper.ROLE); 066 } 067 068 /** 069 * Parses the view of the given content type from the configurations 070 * @param contentType the content type 071 * @param viewConfigurationsByType the view's configurations, indexed by the content types defining this view 072 * @return the parsed view 073 * @throws ConfigurationException if the configuration is invalid 074 */ 075 public View parseView(ContentType contentType, ViewConfigurationsByType viewConfigurationsByType) throws ConfigurationException 076 { 077 // Check that there is at least one main configuration 078 if (viewConfigurationsByType.mainConfigurations().isEmpty()) 079 { 080 throw new ConfigurationException ("There is no main configuration but only overrides for view '" + viewConfigurationsByType.viewName() + "' in content type '" + contentType.getId() + "'"); 081 } 082 083 // Parse View from main configurations 084 List<View> views = new ArrayList<>(); 085 for (ContentType originalContentType : viewConfigurationsByType.mainConfigurations().keySet()) 086 { 087 View view = _parseView(contentType, originalContentType, viewConfigurationsByType.mainConfigurations().get(originalContentType)); 088 views.add(view); 089 } 090 View view = _contentTypesHelper.joinViews(views); 091 092 // Parse overrides 093 for (ContentType originalContentType : viewConfigurationsByType.overrides().keySet()) 094 { 095 for (ConfigurationAndPluginName configuration : viewConfigurationsByType.overrides().get(originalContentType)) 096 { 097 view = _overrideView(contentType, originalContentType, configuration, view); 098 } 099 } 100 101 return view; 102 } 103 104 private View _parseView(ContentType contentType, ContentType originalContentType, ConfigurationAndPluginName viewConfiguration) throws ConfigurationException 105 { 106 ViewParser parser = _getContentTypeViewParser(contentType, originalContentType, viewConfiguration.configuration()); 107 try 108 { 109 LifecycleHelper.setupComponent(parser, getLogger(), _context, _manager, null); 110 return parser.parseView(viewConfiguration); 111 } 112 catch (Exception e) 113 { 114 throw new ConfigurationException("Unable to initialize the content view parser", viewConfiguration.configuration(), e); 115 } 116 finally 117 { 118 LifecycleHelper.dispose(parser); 119 } 120 } 121 122 private View _overrideView(ContentType contentType, ContentType originalContentType, ConfigurationAndPluginName viewConfiguration, View existingView) throws ConfigurationException 123 { 124 ViewParser parser = _getContentTypeViewParser(contentType, originalContentType, viewConfiguration.configuration()); 125 try 126 { 127 LifecycleHelper.setupComponent(parser, getLogger(), _context, _manager, null); 128 return parser.overrideView(viewConfiguration, existingView); 129 } 130 catch (Exception e) 131 { 132 throw new ConfigurationException("Unable to initialize the content view parser", viewConfiguration.configuration(), e); 133 } 134 finally 135 { 136 LifecycleHelper.dispose(parser); 137 } 138 } 139 140 private ViewParser _getContentTypeViewParser(ContentType contentType, ContentType originalContentType, Configuration viewConfiguration) 141 { 142 return ContentType.VIEW_TAG_NAME.equals(viewConfiguration.getName()) 143 ? new ContentTypeViewParser(contentType, originalContentType) 144 : new ContentTypeViewParser(contentType, originalContentType, Optional.of(ContentType.GROUP_TAG_NAME_WITH_LEGACY_SYNTAX), Optional.of(ContentType.ATTRIBUTE_REF_TAG_NAME_WITH_LEGACY_SYNTAX), Optional.empty(), false); 145 } 146 147 /** 148 * Parse an i18n text. 149 * @param configurationAndPluginName the configuration to use. 150 * @param name the child name. 151 * @return the i18n text. 152 * @throws ConfigurationException if the configuration is not valid. 153 */ 154 public I18nizableText parseI18nizableText(ConfigurationAndPluginName configurationAndPluginName, String name) throws ConfigurationException 155 { 156 return parseI18nizableText(configurationAndPluginName, name, StringUtils.EMPTY); 157 } 158 159 /** 160 * Parse an i18n text. 161 * @param configurationAndPluginName the configuration to use. 162 * @param name the child name. 163 * @param defaultValue the default value if no present 164 * @return the i18n text. 165 * @throws ConfigurationException if the configuration is not valid. 166 */ 167 public I18nizableText parseI18nizableText(ConfigurationAndPluginName configurationAndPluginName, String name, String defaultValue) throws ConfigurationException 168 { 169 return I18nizableText.parseI18nizableText(configurationAndPluginName.configuration().getChild(name), "plugin." + configurationAndPluginName.pluginName(), defaultValue); 170 } 171 172 /** 173 * Parse an i18n text. 174 * @param configurationAndPluginName the configuration to use. 175 * @param name the child name. 176 * @param defaultValue the default value if no present 177 * @return the i18n text. 178 * @throws ConfigurationException if the configuration is not valid. 179 */ 180 public I18nizableText parseI18nizableText(ConfigurationAndPluginName configurationAndPluginName, String name, I18nizableText defaultValue) throws ConfigurationException 181 { 182 return I18nizableText.parseI18nizableText(configurationAndPluginName.configuration().getChild(name), "plugin." + configurationAndPluginName.pluginName(), defaultValue); 183 } 184 185 186 /** 187 * Parse an icon path 188 * @param contentType the content type 189 * @param configuration the configuration to use 190 * @param name the child name. 191 * @return The icon path 192 * @throws ConfigurationException if the configuration is not valid. 193 */ 194 public String parseIcon (ContentTypeDescriptor contentType, Configuration configuration, String name) throws ConfigurationException 195 { 196 return parseIcon(contentType, configuration, name, "/plugins/cms/resources/img/contenttype/unknown-" + name + ".png"); 197 } 198 199 /** 200 * Parse an icon path 201 * @param contentType the content type 202 * @param configuration the configuration to use 203 * @param name the child name. 204 * @param defaultValue the default value. 205 * @return The icon path 206 * @throws ConfigurationException if the configuration is not valid. 207 */ 208 public String parseIcon(ContentTypeDescriptor contentType, Configuration configuration, String name, String defaultValue) throws ConfigurationException 209 { 210 Configuration iconConfig = configuration.getChild(name, false); 211 if (iconConfig != null) 212 { 213 String pluginName = iconConfig.getAttribute("plugin", contentType.getPluginName()); 214 return contentType.getIconPath(pluginName) + iconConfig.getValue(); 215 } 216 217 return defaultValue; 218 } 219 220 /** 221 * Retrieves the default value for the view's icon glyph. 222 * For all views, use medium icon or a default one. 223 * For some common views (main, abstract, link), a specific default icon is used 224 * @param viewName the name of the view 225 * @param mediumIcon the medium icon of the view 226 * @return the default value for the view's icon glyph. 227 */ 228 public String getIconGlyphDefaultValue(String viewName, String mediumIcon) 229 { 230 String defaultValue = StringUtils.defaultString(mediumIcon, "ametysicon-column3"); 231 switch (viewName) 232 { 233 case "main": 234 defaultValue = "ametysicon-document112"; 235 break; 236 case "abstract": 237 defaultValue = "ametysicon-document77"; 238 break; 239 case "link": 240 defaultValue = "ametysicon-internet58"; 241 break; 242 default: 243 break; 244 } 245 246 return defaultValue; 247 } 248}