001/* 002 * Copyright 2023 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.web.repository.page.virtual; 017 018import java.util.Locale; 019 020import javax.xml.transform.TransformerConfigurationException; 021import javax.xml.transform.TransformerFactory; 022import javax.xml.transform.TransformerFactoryConfigurationError; 023import javax.xml.transform.dom.DOMResult; 024import javax.xml.transform.sax.SAXTransformerFactory; 025import javax.xml.transform.sax.TransformerHandler; 026 027import org.apache.avalon.framework.configuration.Configuration; 028import org.apache.avalon.framework.configuration.ConfigurationException; 029import org.apache.avalon.framework.configuration.DefaultConfigurationSerializer; 030import org.w3c.dom.Document; 031import org.w3c.dom.Element; 032import org.xml.sax.SAXException; 033 034import org.ametys.cms.data.holder.impl.DefaultModifiableModelAwareDataHolder; 035import org.ametys.cms.repository.Content; 036import org.ametys.cms.transformation.Configuration2XMLValuesTransformer; 037import org.ametys.plugins.repository.AmetysRepositoryException; 038import org.ametys.plugins.repository.data.extractor.ModelAwareValuesExtractor; 039import org.ametys.plugins.repository.data.extractor.xml.ModelAwareXMLValuesExtractor; 040import org.ametys.plugins.repository.data.holder.ModelAwareDataHolder; 041import org.ametys.plugins.repository.data.holder.ModelLessDataHolder; 042import org.ametys.plugins.repository.data.holder.ModifiableModelAwareDataHolder; 043import org.ametys.plugins.repository.data.holder.impl.DefaultModelLessDataHolder; 044import org.ametys.plugins.repository.data.repositorydata.ModifiableRepositoryData; 045import org.ametys.plugins.repository.data.repositorydata.RepositoryData; 046import org.ametys.plugins.repository.data.repositorydata.impl.MemoryRepositoryData; 047import org.ametys.runtime.model.type.DataContext; 048import org.ametys.web.repository.page.Zone; 049import org.ametys.web.repository.page.ZoneItem; 050import org.ametys.web.service.Service; 051 052/** 053 * A configurable zone item 054 */ 055public class ConfigurableVirtualZoneItem implements ZoneItem 056{ 057 /** The AbstractVirtualConfigurablePage */ 058 protected AbstractConfigurableVirtualPage _page; 059 /** The zone item name */ 060 protected String _name; 061 /** The VirtualPageZoneItemConfiguration */ 062 protected VirtualZoneItemConfiguration _configuration; 063 /** The VirtualPageZoneConfiguration */ 064 protected VirtualZoneConfiguration _zoneConfiguration; 065 /** The ZoneType */ 066 protected ZoneType _zoneType; 067 /** The scheme */ 068 private String _scheme; 069 /** The factory */ 070 private ConfigurableVirtualZoneItemFactory _factory; 071 072 073 /** 074 * The constructor of a configurable zone item 075 * @param page The AbstractVirtualConfigurablePage page 076 * @param configuration The virtual page's zone item's configuration 077 * @param scheme The scheme 078 * @param factory The factory 079 */ 080 public ConfigurableVirtualZoneItem(AbstractConfigurableVirtualPage page, VirtualZoneItemConfiguration configuration, String scheme, ConfigurableVirtualZoneItemFactory factory) 081 { 082 _configuration = configuration; 083 _zoneConfiguration = _configuration.getParentZoneConfiguration(); 084 _page = page; 085 _name = _configuration.getName(); 086 _zoneType = configuration.getZoneType(); 087 _scheme = scheme; 088 _factory = factory; 089 } 090 091 @Override 092 public String getViewName() throws AmetysRepositoryException 093 { 094 return _configuration.getView(); 095 } 096 097 @Override 098 public String getName() throws AmetysRepositoryException 099 { 100 return _name; 101 } 102 103 @Override 104 public String getPath() throws AmetysRepositoryException 105 { 106 return getParentPath() + "/ametys-internal:zoneItems/" + _configuration.getName(); 107 } 108 109 @Override 110 public String getParentPath() throws AmetysRepositoryException 111 { 112 return _page.getPath() + "/ametys-internal:zones/" + _configuration.getParentZoneName(); 113 } 114 115 @Override 116 public ZoneType getType() throws AmetysRepositoryException 117 { 118 return _zoneType; 119 } 120 121 @SuppressWarnings("unchecked") 122 @Override 123 public <C extends Content> C getContent() throws AmetysRepositoryException 124 { 125 if (_zoneType.equals(ZoneType.CONTENT)) 126 { 127 return (C) _page.getContent(); 128 } 129 130 throw new UnsupportedOperationException("This zoneitem is not a content zoneitem on this virtual page"); 131 } 132 133 @Override 134 public String getServiceId() throws AmetysRepositoryException 135 { 136 if (_zoneType.equals(ZoneType.SERVICE)) 137 { 138 return _configuration.getServiceId(); 139 } 140 141 throw new UnsupportedOperationException("This zoneitem is not a service zoneitem on this virtual page"); 142 } 143 144 @Override 145 public ModelAwareDataHolder getServiceParameters() throws AmetysRepositoryException 146 { 147 if (_zoneType.equals(ZoneType.SERVICE)) 148 { 149 ModifiableRepositoryData repositoryData = new MemoryRepositoryData(SERVICE_PARAMETERS_DATA_NAME); 150 Service service = _factory.getServiceExtensionPoint().getExtension(getServiceId()); 151 if (service == null) 152 { 153 throw new IllegalStateException("The virtual page is using the unexisting service '" + getServiceId() + "'"); 154 } 155 156 ModifiableModelAwareDataHolder dataHolder = new DefaultModifiableModelAwareDataHolder(repositoryData, service); 157 158 DataContext dataContext = DataContext.newInstance(); 159 dataContext.withLocale(Locale.forLanguageTag(getParent().getSitemapElement().getSitemapName())); 160 161 try 162 { 163 // Configuration may requires interpretation before extraction of the value 164 // for example to translate i18n keys 165 Element xmlValues = _interpretConfiguration(_configuration.getConfiguration(), dataContext); 166 167 // provide the result to XML values extractor 168 ModelAwareValuesExtractor extractor = new ModelAwareXMLValuesExtractor(xmlValues, service); 169 dataHolder.synchronizeValues(extractor.extractValues()); 170 } 171 catch (Exception e) 172 { 173 throw new AmetysRepositoryException("An error occured while retrieving service parameters of the virtual page '" + _page.getId() + "'", e); 174 } 175 176 return dataHolder; 177 } 178 179 throw new UnsupportedOperationException("This zoneitem is not a service zoneitem on this virtual page"); 180 } 181 182 private Element _interpretConfiguration(Configuration contentCfg, DataContext dataContext) 183 throws SAXException, ConfigurationException 184 { 185 DOMResult domResult = new DOMResult(); 186 187 try 188 { 189 TransformerHandler th = ((SAXTransformerFactory) TransformerFactory.newInstance()).newTransformerHandler(); 190 th.setResult(domResult); 191 192 Configuration2XMLValuesTransformer handler = new Configuration2XMLValuesTransformer(th, dataContext, _factory.getI18nUtils()); 193 new DefaultConfigurationSerializer().serialize(handler, contentCfg); 194 Element values = ((Document) domResult.getNode()).getDocumentElement(); 195 return values; 196 } 197 catch (TransformerConfigurationException | TransformerFactoryConfigurationError e) 198 { 199 throw new IllegalStateException("Failed to retrive transformer handler. Impossible to interpret the configuration", e); 200 } 201 } 202 203 @Override 204 public ModelLessDataHolder getDataHolder() 205 { 206 RepositoryData repositoryData = new MemoryRepositoryData(Zone.ZONEITEM_DATA_NAME); 207 return new DefaultModelLessDataHolder(_factory.getZoneItemDataTypeExtensionPoint(), repositoryData); 208 } 209 210 @Override 211 public String getId() throws AmetysRepositoryException 212 { 213 return _scheme + "://" + _name + "?pageId=" + _page.getId() + "&zoneId=" + _zoneConfiguration.getId(); 214 } 215 216 @SuppressWarnings("unchecked") 217 @Override 218 public Zone getParent() throws AmetysRepositoryException 219 { 220 return getZone(); 221 } 222 223 @Override 224 public Zone getZone() 225 { 226 return _factory.getZoneFactory().createZone(_page, _zoneConfiguration.getId()); 227 } 228 229 @Override 230 public ModelAwareDataHolder getZoneItemParametersHolder() throws AmetysRepositoryException 231 { 232 // No parameters are available on virtual zone item 233 return null; 234 } 235 236 @Override 237 public ModelAwareDataHolder getContentViewParametersHolder(String contentViewName) throws AmetysRepositoryException 238 { 239 // No parameters are available on virtual zone item 240 return null; 241 } 242 243 @Override 244 public ModelAwareDataHolder getServiceViewParametersHolder(String serviceViewName) throws AmetysRepositoryException 245 { 246 // No parameters are available on virtual zone item 247 return null; 248 } 249}