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