001/* 002 * Copyright 2018 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; 017 018import java.io.IOException; 019import java.util.Collection; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023import java.util.Optional; 024 025import org.apache.avalon.framework.component.Component; 026import org.apache.avalon.framework.context.Context; 027import org.apache.avalon.framework.context.ContextException; 028import org.apache.avalon.framework.context.Contextualizable; 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.ProcessingException; 033import org.apache.cocoon.components.ContextHelper; 034import org.apache.cocoon.environment.Request; 035import org.apache.commons.lang.StringUtils; 036 037import org.ametys.core.observation.Event; 038import org.ametys.core.observation.ObservationManager; 039import org.ametys.core.ui.Callable; 040import org.ametys.core.user.CurrentUserProvider; 041import org.ametys.plugins.repository.AmetysObjectResolver; 042import org.ametys.plugins.repository.UnknownAmetysObjectException; 043import org.ametys.plugins.repository.data.holder.ModelAwareDataHolder; 044import org.ametys.plugins.repository.data.holder.ModifiableModelAwareDataHolder; 045import org.ametys.runtime.i18n.I18nizableText; 046import org.ametys.runtime.model.ModelItem; 047import org.ametys.runtime.model.View; 048import org.ametys.runtime.model.ViewItem; 049import org.ametys.runtime.model.ViewItemContainer; 050import org.ametys.runtime.plugin.component.AbstractLogEnabled; 051import org.ametys.web.ObservationConstants; 052import org.ametys.web.WebConstants; 053import org.ametys.web.parameters.ParametersManager; 054import org.ametys.web.parameters.view.ViewParametersModel; 055import org.ametys.web.parameters.view.ViewParametersDAO; 056import org.ametys.web.parameters.view.ViewParametersManager; 057import org.ametys.web.repository.page.Page.PageType; 058import org.ametys.web.repository.page.ZoneItem.ZoneType; 059import org.ametys.web.service.Service; 060import org.ametys.web.service.ServiceExtensionPoint; 061 062/** 063 * Class containing callables to retrieve and configure service parameters 064 */ 065public class ZoneItemManager extends AbstractLogEnabled implements Component, Serviceable, Contextualizable 066{ 067 /** Avalon Role */ 068 public static final String ROLE = ZoneItemManager.class.getName(); 069 070 /** Constant for untouched binary metadata. */ 071 protected static final String __SERVICE_PARAM_UNTOUCHED_BINARY = "untouched"; 072 073 private ServiceExtensionPoint _serviceExtensionPoint; 074 private AmetysObjectResolver _resolver; 075 private ObservationManager _observationManager; 076 private CurrentUserProvider _currentUserProvider; 077 private ParametersManager _parametersManager; 078 private ViewParametersManager _viewParametersManager; 079 private Context _context; 080 081 public void service(ServiceManager manager) throws ServiceException 082 { 083 _serviceExtensionPoint = (ServiceExtensionPoint) manager.lookup(ServiceExtensionPoint.ROLE); 084 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 085 _observationManager = (ObservationManager) manager.lookup(ObservationManager.ROLE); 086 _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 087 _parametersManager = (ParametersManager) manager.lookup(ParametersManager.ROLE); 088 _viewParametersManager = (ViewParametersManager) manager.lookup(ViewParametersManager.ROLE); 089 } 090 091 public void contextualize(Context context) throws ContextException 092 { 093 _context = context; 094 } 095 096 /** 097 * Retrieves the parameter definitions of the given service 098 * @param serviceId Identifier of the service 099 * @param pageId the page id 100 * @param zoneItemId the zone item id 101 * @param zoneName the zone name 102 * @return the parameter definitions 103 * @throws ProcessingException if an error occurs 104 */ 105 @Callable 106 public Map<String, Object> getServiceParameterDefinitions(String serviceId, String pageId, String zoneItemId, String zoneName) throws ProcessingException 107 { 108 _setRequestAttribute(serviceId, pageId, zoneItemId, zoneName); 109 110 Map<String, Object> response = new HashMap<>(); 111 112 Service service = _serviceExtensionPoint.getExtension(serviceId); 113 114 response.put("id", serviceId); 115 response.put("url", service.getURL()); 116 response.put("label", service.getLabel()); 117 response.put("height", service.getCreationBoxHeight()); 118 response.put("width", service.getCreationBoxWidth()); 119 120 View serviceView = service.getView(); 121 122 Page page = _resolver.resolveById(pageId); 123 124 Map<String, ViewParametersModel> serviceViewParametersModels = _viewParametersManager.getServiceViewParametersModels(page.getSite().getSkinId(), serviceId); 125 126 ViewItemContainer viewContainer = _getXSLTViewItemContainer(serviceView); 127 if (viewContainer != null) 128 { 129 for (String viewName : serviceViewParametersModels.keySet()) 130 { 131 ViewParametersModel viewParameters = serviceViewParametersModels.get(viewName); 132 Collection< ? extends ModelItem> modelItems = viewParameters.getModelItems(); 133 134 String prefix = ViewParametersDAO.PREFIX_SERVICE + ViewParametersDAO.MODEL_ITEM_NAME_SEPARATOR + _viewParametersManager.normalizeViewName(viewName) + ViewParametersDAO.MODEL_ITEM_NAME_SEPARATOR; 135 List<ModelItem> includeModelItems = _viewParametersManager.includeModelItems(modelItems, prefix, viewContainer); 136 _viewParametersManager.setDisableConditions(ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME, viewName, includeModelItems); 137 } 138 } 139 140 response.put("parameters", serviceView.toJSON()); 141 142 return response; 143 } 144 145 private ViewItemContainer _getXSLTViewItemContainer(ViewItemContainer viewItemContainer) 146 { 147 for (ViewItem viewItem : viewItemContainer.getViewItems()) 148 { 149 if (ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME.equals(viewItem.getName())) 150 { 151 return viewItemContainer; 152 } 153 else if (viewItem instanceof ViewItemContainer) 154 { 155 ViewItemContainer xsltViewItemContainer = _getXSLTViewItemContainer((ViewItemContainer) viewItem); 156 if (xsltViewItemContainer != null) 157 { 158 return xsltViewItemContainer; 159 } 160 } 161 } 162 163 return null; 164 } 165 166 private void _setRequestAttribute(String serviceId, String pageId, String zoneItemId, String zoneName) 167 { 168 Request request = ContextHelper.getRequest(_context); 169 170 request.setAttribute(WebConstants.REQUEST_ATTR_SERVICE_ID, serviceId); 171 request.setAttribute(WebConstants.REQUEST_ATTR_PAGE_ID, pageId); 172 request.setAttribute(WebConstants.REQUEST_ATTR_ZONEITEM_ID, zoneItemId); 173 request.setAttribute(WebConstants.REQUEST_ATTR_ZONE_NAME, zoneName); 174 } 175 176 /** 177 * Get the service parameter values 178 * @param zoneItemId the zone item id 179 * @param serviceId the service Id 180 * @return the values 181 */ 182 @Callable 183 public Map<String, Object> getServiceParameterValues(String zoneItemId, String serviceId) 184 { 185 Service service = _serviceExtensionPoint.getExtension(serviceId); 186 ZoneItem zoneItem = _resolver.resolveById(zoneItemId); 187 188 Map<String, Object> response = new HashMap<>(); 189 Collection<ModelItem> serviceParameterDefinitions = service.getParameters().values(); 190 ModelAwareDataHolder dataHolder = zoneItem.getServiceParameters(); 191 192 Map<String, Object> values = _parametersManager.getParametersValues(serviceParameterDefinitions, dataHolder, ""); 193 values.putAll(_getServiceViewParametersValues(zoneItem)); 194 195 response.put("values", values); 196 197 List<Map<String, Object>> repeaters = _parametersManager.getRepeatersValues(serviceParameterDefinitions, dataHolder, ""); 198 response.put("repeaters", repeaters); 199 200 return response; 201 } 202 203 /** 204 * Get the service view parameters values 205 * @param zoneItem the zone item 206 * @return the values 207 */ 208 protected Map<String, Object> _getServiceViewParametersValues(ZoneItem zoneItem) 209 { 210 Map<String, Object> values = new HashMap<>(); 211 212 String skinId = zoneItem.getZone() 213 .getPage() 214 .getSite() 215 .getSkinId(); 216 217 Map<String, ViewParametersModel> serviceViewParametersModels = _viewParametersManager.getServiceViewParametersModels(skinId, zoneItem.getServiceId()); 218 for (String viewName : serviceViewParametersModels.keySet()) 219 { 220 ViewParametersModel serviceViewParameters = serviceViewParametersModels.get(viewName); 221 ModelAwareDataHolder serviceViewParametersHolder = zoneItem.getServiceViewParametersHolder(viewName); 222 223 Map<String, Object> serviceValues = _parametersManager.getParametersValues(serviceViewParameters.getModelItems(), serviceViewParametersHolder, ""); 224 String prefix = ViewParametersDAO.PREFIX_SERVICE + ViewParametersDAO.MODEL_ITEM_NAME_SEPARATOR + _viewParametersManager.normalizeViewName(viewName) + ViewParametersDAO.MODEL_ITEM_NAME_SEPARATOR; 225 values.putAll(_parametersManager.addPrefixToParameters(serviceValues, prefix)); 226 } 227 228 return values; 229 } 230 231 /** 232 * Add the service to the given zone on given page 233 * @param pageId The page identifier 234 * @param zoneName The zone name 235 * @param serviceId The identifier of the service to add 236 * @param parameterValues the service parameter values. Can be empty 237 * @return The result with the identifiers of updated page, zone and zone item 238 * @throws IOException if an error occurred while saving parameters 239 */ 240 @Callable 241 public Map<String, Object> addService(String pageId, String zoneName, String serviceId, Map<String, Object> parameterValues) throws IOException 242 { 243 if (StringUtils.isEmpty(serviceId) || StringUtils.isEmpty(pageId) || StringUtils.isEmpty(zoneName)) 244 { 245 throw new IllegalArgumentException("ServiceId, PageId or ZoneName is missing"); 246 } 247 248 // Check the service 249 Service service = null; 250 try 251 { 252 service = _serviceExtensionPoint.getExtension(serviceId); 253 } 254 catch (IllegalArgumentException e) 255 { 256 throw new IllegalArgumentException("Service with id '" + serviceId + "' does not exist", e); 257 } 258 259 try 260 { 261 Page page = _resolver.resolveById(pageId); 262 if (!(page instanceof ModifiablePage)) 263 { 264 throw new IllegalArgumentException("Can not affect service on a non-modifiable page " + pageId); 265 } 266 267 ModifiablePage modifiablePage = (ModifiablePage) page; 268 269 if (page.getType() != PageType.CONTAINER) 270 { 271 throw new IllegalArgumentException("Can not affect service on a non-container page " + pageId); 272 } 273 274 ModifiableZone zone; 275 if (page.hasZone(zoneName)) 276 { 277 zone = modifiablePage.getZone(zoneName); 278 } 279 else 280 { 281 zone = modifiablePage.createZone(zoneName); 282 } 283 284 ModifiableZoneItem zoneItem = zone.addZoneItem(); 285 zoneItem.setType(ZoneType.SERVICE); 286 zoneItem.setServiceId(serviceId); 287 288 Map<String, List<I18nizableText>> allErrors = _setParameterValues(parameterValues, service, zoneItem); 289 290 Map<String, Object> results = new HashMap<>(); 291 if (!allErrors.isEmpty()) 292 { 293 results.put("errors", allErrors); 294 return results; 295 } 296 297 modifiablePage.saveChanges(); 298 299 Map<String, Object> eventParams = new HashMap<>(); 300 eventParams.put(ObservationConstants.ARGS_PAGE, page); 301 eventParams.put(ObservationConstants.ARGS_ZONE_ITEM_ID, zoneItem.getId()); 302 eventParams.put(ObservationConstants.ARGS_ZONE_TYPE, ZoneType.SERVICE); 303 _observationManager.notify(new Event(ObservationConstants.EVENT_ZONEITEM_ADDED, _currentUserProvider.getUser(), eventParams)); 304 305 results.put("id", page.getId()); 306 results.put("zoneitem-id", zoneItem.getId()); 307 results.put("zone-name", zone.getName()); 308 309 return results; 310 } 311 catch (UnknownAmetysObjectException e) 312 { 313 throw new IllegalArgumentException("An error occured adding the service '" + serviceId + "' on the page '" + pageId + "'", e); 314 } 315 } 316 317 /** 318 * Edit the parameter values of the given service 319 * @param zoneItemId The identifier of the zone item holding the service 320 * @param serviceId The service identifier 321 * @param parameterValues the service parameter values to update 322 * @return The result with the identifiers of updated page, zone and zone item 323 * @throws IOException if an error occurs while saving parameters 324 */ 325 @Callable 326 public Map<String, Object> editServiceParameterValues(String zoneItemId, String serviceId, Map<String, Object> parameterValues) throws IOException 327 { 328 Service service = null; 329 try 330 { 331 service = _serviceExtensionPoint.getExtension(serviceId); 332 } 333 catch (IllegalArgumentException e) 334 { 335 throw new IllegalArgumentException("Service with id '" + serviceId + "' does not exist", e); 336 } 337 338 ZoneItem zoneItem = _resolver.resolveById(zoneItemId); 339 if (!(zoneItem instanceof ModifiableZoneItem)) 340 { 341 throw new IllegalArgumentException("Can not configure service on a non-modifiable zone item " + zoneItemId); 342 } 343 344 ModifiableZoneItem modifiableZoneItem = (ModifiableZoneItem) zoneItem; 345 346 Map<String, List<I18nizableText>> allErrors = _setParameterValues(parameterValues, service, modifiableZoneItem); 347 348 Map<String, Object> results = new HashMap<>(); 349 if (!allErrors.isEmpty()) 350 { 351 results.put("errors", allErrors); 352 return results; 353 } 354 355 modifiableZoneItem.saveChanges(); 356 357 Map<String, Object> eventParams = new HashMap<>(); 358 eventParams.put(ObservationConstants.ARGS_ZONE_ITEM, zoneItem); 359 eventParams.put(ObservationConstants.ARGS_ZONE_ITEM_ID, zoneItem.getId()); 360 _observationManager.notify(new Event(ObservationConstants.EVENT_SERVICE_MODIFIED, _currentUserProvider.getUser(), eventParams)); 361 362 results.put("id", zoneItem.getZone().getPage().getId()); 363 results.put("zoneitem-id", zoneItem.getId()); 364 results.put("zone-name", zoneItem.getZone().getName()); 365 366 return results; 367 } 368 369 /** 370 * Set the parameter values for the service (with view parameters) 371 * @param parameterValues the parameter values 372 * @param service the service 373 * @param zoneItem the zone item 374 * @return the map of error 375 */ 376 protected Map<String, List<I18nizableText>> _setParameterValues(Map<String, Object> parameterValues, Service service, ModifiableZoneItem zoneItem) 377 { 378 ModifiableModelAwareDataHolder serviceDataHolder = zoneItem.getServiceParameters(); 379 Map<String, ModelItem> definitions = service.getParameters(); 380 Map<String, List<I18nizableText>> allErrors = _parametersManager.setParameterValues(serviceDataHolder, definitions.values(), parameterValues); 381 382 if (parameterValues.containsKey(ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME)) 383 { 384 String viewName = (String) parameterValues.get(ViewParametersManager.SERVICE_VIEW_DEFAULT_MODEL_ITEM_NAME); 385 386 String skinId = zoneItem.getZone() 387 .getPage() 388 .getSite() 389 .getSkinId(); 390 Optional<ViewParametersModel> serviceViewParametersModel = _viewParametersManager.getServiceViewParametersModel(skinId, service.getId(), viewName); 391 392 if (serviceViewParametersModel.isPresent()) 393 { 394 ModifiableModelAwareDataHolder serviceParametersHolder = zoneItem.getServiceViewParametersHolder(viewName); 395 String prefix = ViewParametersDAO.PREFIX_SERVICE + ViewParametersDAO.MODEL_ITEM_NAME_SEPARATOR + _viewParametersManager.normalizeViewName(viewName) + ViewParametersDAO.MODEL_ITEM_NAME_SEPARATOR; 396 Map<String, Object> viewParametersValues = _parametersManager.getParametersStartWithPrefix(parameterValues, prefix); 397 allErrors.putAll(_parametersManager.setParameterValues(serviceParametersHolder, serviceViewParametersModel.get().getModelItems(), viewParametersValues)); 398 } 399 } 400 401 return allErrors; 402 } 403}