001/* 002 * (C) Copyright 2010 Nuxeo SA (http://nuxeo.com/) and others. 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 * 016 * Contributors: 017 * Anahide Tchertchian 018 */ 019package org.nuxeo.ecm.platform.forms.layout.core.service; 020 021import java.util.ArrayList; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.HashMap; 025import java.util.HashSet; 026import java.util.List; 027import java.util.Map; 028import java.util.Set; 029 030import org.apache.commons.logging.Log; 031import org.apache.commons.logging.LogFactory; 032import org.nuxeo.ecm.platform.forms.layout.api.LayoutDefinition; 033import org.nuxeo.ecm.platform.forms.layout.api.LayoutTypeDefinition; 034import org.nuxeo.ecm.platform.forms.layout.api.WidgetDefinition; 035import org.nuxeo.ecm.platform.forms.layout.api.WidgetType; 036import org.nuxeo.ecm.platform.forms.layout.api.WidgetTypeDefinition; 037import org.nuxeo.ecm.platform.forms.layout.api.converters.LayoutDefinitionConverter; 038import org.nuxeo.ecm.platform.forms.layout.api.converters.WidgetDefinitionConverter; 039import org.nuxeo.ecm.platform.forms.layout.api.impl.WidgetTypeImpl; 040import org.nuxeo.ecm.platform.forms.layout.api.service.LayoutStore; 041import org.nuxeo.ecm.platform.forms.layout.core.registries.LayoutConverterRegistry; 042import org.nuxeo.ecm.platform.forms.layout.core.registries.LayoutDefinitionRegistry; 043import org.nuxeo.ecm.platform.forms.layout.core.registries.LayoutTypeDefinitionRegistry; 044import org.nuxeo.ecm.platform.forms.layout.core.registries.WidgetConverterRegistry; 045import org.nuxeo.ecm.platform.forms.layout.core.registries.WidgetDefinitionRegistry; 046import org.nuxeo.ecm.platform.forms.layout.core.registries.WidgetTypeDefinitionRegistry; 047import org.nuxeo.ecm.platform.forms.layout.core.registries.WidgetTypeRegistry; 048import org.nuxeo.ecm.platform.forms.layout.descriptors.LayoutConverterDescriptor; 049import org.nuxeo.ecm.platform.forms.layout.descriptors.LayoutDescriptor; 050import org.nuxeo.ecm.platform.forms.layout.descriptors.LayoutTypeDescriptor; 051import org.nuxeo.ecm.platform.forms.layout.descriptors.WidgetConverterDescriptor; 052import org.nuxeo.ecm.platform.forms.layout.descriptors.WidgetDescriptor; 053import org.nuxeo.ecm.platform.forms.layout.descriptors.WidgetTypeDescriptor; 054import org.nuxeo.runtime.model.ComponentInstance; 055import org.nuxeo.runtime.model.DefaultComponent; 056 057/** 058 * @author Anahide Tchertchian 059 * @since 5.5 060 */ 061public class LayoutStoreImpl extends DefaultComponent implements LayoutStore { 062 063 private static final Log log = LogFactory.getLog(LayoutStoreImpl.class); 064 065 private static final long serialVersionUID = 1L; 066 067 public static final String WIDGET_TYPES_EP_NAME = "widgettypes"; 068 069 /** 070 * @since 6.0 071 */ 072 public static final String LAYOUT_TYPES_EP_NAME = "layouttypes"; 073 074 public static final String WIDGETS_EP_NAME = "widgets"; 075 076 public static final String LAYOUTS_EP_NAME = "layouts"; 077 078 public static final String LAYOUT_CONVERTERS_EP_NAME = "layoutConverters"; 079 080 public static final String WIDGET_CONVERTERS_EP_NAME = "widgetConverters"; 081 082 protected final Map<String, WidgetTypeRegistry> widgetTypesByCat; 083 084 protected final Map<String, WidgetTypeDefinitionRegistry> widgetTypeDefsByCat; 085 086 protected final Map<String, LayoutTypeDefinitionRegistry> layoutTypeDefsByCat; 087 088 protected final Map<String, LayoutDefinitionRegistry> layoutsByCat; 089 090 protected final Map<String, WidgetDefinitionRegistry> widgetsByCat; 091 092 protected final Map<String, WidgetConverterRegistry> widgetConvertersByCat; 093 094 protected final Map<String, LayoutConverterRegistry> layoutConvertersByCat; 095 096 public LayoutStoreImpl() { 097 widgetTypeDefsByCat = new HashMap<String, WidgetTypeDefinitionRegistry>(); 098 layoutTypeDefsByCat = new HashMap<String, LayoutTypeDefinitionRegistry>(); 099 widgetTypesByCat = new HashMap<String, WidgetTypeRegistry>(); 100 layoutsByCat = new HashMap<String, LayoutDefinitionRegistry>(); 101 widgetsByCat = new HashMap<String, WidgetDefinitionRegistry>(); 102 widgetConvertersByCat = new HashMap<String, WidgetConverterRegistry>(); 103 layoutConvertersByCat = new HashMap<String, LayoutConverterRegistry>(); 104 } 105 106 // Runtime component API 107 108 @Override 109 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 110 if (extensionPoint.equals(WIDGET_TYPES_EP_NAME)) { 111 WidgetTypeDescriptor desc = (WidgetTypeDescriptor) contribution; 112 String[] categories = desc.getCategories(); 113 if (categories == null || categories.length == 0) { 114 log.error(String.format("Cannot register widget type '%s': no category found", desc.getName())); 115 } else { 116 for (String cat : categories) { 117 registerWidgetType(cat, desc.getWidgetTypeDefinition()); 118 } 119 } 120 } else if (extensionPoint.equals(LAYOUT_TYPES_EP_NAME)) { 121 LayoutTypeDescriptor desc = (LayoutTypeDescriptor) contribution; 122 String[] categories = desc.getCategories(); 123 if (categories == null || categories.length == 0) { 124 log.error(String.format("Cannot register layout type '%s': no category found", desc.getName())); 125 } else { 126 for (String cat : categories) { 127 registerLayoutType(cat, desc.getLayoutTypeDefinition()); 128 } 129 } 130 } else if (extensionPoint.equals(LAYOUTS_EP_NAME)) { 131 LayoutDescriptor desc = (LayoutDescriptor) contribution; 132 String[] categories = desc.getCategories(); 133 if (categories == null || categories.length == 0) { 134 log.error(String.format("Cannot register layout '%s': no category found", desc.getName())); 135 } else { 136 for (String cat : categories) { 137 registerLayout(cat, desc.getLayoutDefinition()); 138 } 139 } 140 } else if (extensionPoint.equals(WIDGETS_EP_NAME)) { 141 WidgetDescriptor desc = (WidgetDescriptor) contribution; 142 String[] categories = desc.getCategories(); 143 if (categories == null || categories.length == 0) { 144 log.error(String.format("Cannot register widget '%s': no category found", desc.getName())); 145 } else { 146 for (String cat : categories) { 147 registerWidget(cat, desc.getWidgetDefinition()); 148 } 149 } 150 } else if (extensionPoint.equals(LAYOUT_CONVERTERS_EP_NAME)) { 151 LayoutConverterDescriptor desc = (LayoutConverterDescriptor) contribution; 152 String[] categories = desc.getCategories(); 153 if (categories == null || categories.length == 0) { 154 log.error(String.format("Cannot register layout converter '%s': no category found", desc.getName())); 155 } else { 156 for (String cat : categories) { 157 registerLayoutConverter(cat, desc); 158 } 159 } 160 } else if (extensionPoint.equals(WIDGET_CONVERTERS_EP_NAME)) { 161 WidgetConverterDescriptor desc = (WidgetConverterDescriptor) contribution; 162 String[] categories = desc.getCategories(); 163 if (categories == null || categories.length == 0) { 164 log.error(String.format("Cannot register widget converter '%s': no category found", desc.getName())); 165 } else { 166 for (String cat : categories) { 167 registerWidgetConverter(cat, desc); 168 } 169 } 170 } else { 171 log.error(String.format("Unknown extension point %s, can't register !", extensionPoint)); 172 } 173 } 174 175 @Override 176 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 177 if (extensionPoint.equals(WIDGET_TYPES_EP_NAME)) { 178 WidgetTypeDescriptor desc = (WidgetTypeDescriptor) contribution; 179 String[] categories = desc.getCategories(); 180 if (categories == null || categories.length == 0) { 181 log.error(String.format("Cannot unregister widget type '%s': no category found", desc.getName())); 182 } else { 183 for (String cat : categories) { 184 unregisterWidgetType(cat, desc.getWidgetTypeDefinition()); 185 } 186 } 187 } else if (extensionPoint.equals(LAYOUT_TYPES_EP_NAME)) { 188 LayoutTypeDescriptor desc = (LayoutTypeDescriptor) contribution; 189 String[] categories = desc.getCategories(); 190 if (categories == null || categories.length == 0) { 191 log.error(String.format("Cannot unregister layout type '%s': no category found", desc.getName())); 192 } else { 193 for (String cat : categories) { 194 unregisterLayoutType(cat, desc.getLayoutTypeDefinition()); 195 } 196 } 197 } else if (extensionPoint.equals(LAYOUTS_EP_NAME)) { 198 LayoutDescriptor desc = (LayoutDescriptor) contribution; 199 String[] categories = desc.getCategories(); 200 if (categories == null || categories.length == 0) { 201 log.error(String.format("Cannot unregister layout '%s': no category found", desc.getName())); 202 } else { 203 for (String cat : categories) { 204 unregisterLayout(cat, desc.getLayoutDefinition()); 205 } 206 } 207 } else if (extensionPoint.equals(WIDGETS_EP_NAME)) { 208 WidgetDescriptor desc = (WidgetDescriptor) contribution; 209 String[] categories = desc.getCategories(); 210 if (categories == null || categories.length == 0) { 211 log.error(String.format("Cannot unregister widget '%s': no category found", desc.getName())); 212 } else { 213 for (String cat : categories) { 214 unregisterWidget(cat, desc.getWidgetDefinition()); 215 } 216 } 217 } else if (extensionPoint.equals(LAYOUT_CONVERTERS_EP_NAME)) { 218 LayoutConverterDescriptor desc = (LayoutConverterDescriptor) contribution; 219 String[] categories = desc.getCategories(); 220 if (categories == null || categories.length == 0) { 221 log.error(String.format("Cannot register layout converter '%s': no category found", desc.getName())); 222 } else { 223 for (String cat : categories) { 224 unregisterLayoutConverter(cat, desc); 225 } 226 } 227 } else if (extensionPoint.equals(WIDGET_CONVERTERS_EP_NAME)) { 228 WidgetConverterDescriptor desc = (WidgetConverterDescriptor) contribution; 229 String[] categories = desc.getCategories(); 230 if (categories == null || categories.length == 0) { 231 log.error(String.format("Cannot register widget converter '%s': no category found", desc.getName())); 232 } else { 233 for (String cat : categories) { 234 unregisterWidgetConverter(cat, desc); 235 } 236 } 237 } else { 238 log.error(String.format("Unknown extension point %s, can't unregister !", extensionPoint)); 239 } 240 } 241 242 // Categories 243 244 @Override 245 public List<String> getCategories() { 246 Set<String> cats = new HashSet<String>(); 247 cats.addAll(widgetTypeDefsByCat.keySet()); 248 cats.addAll(widgetTypesByCat.keySet()); 249 cats.addAll(layoutsByCat.keySet()); 250 cats.addAll(widgetsByCat.keySet()); 251 List<String> res = new ArrayList<String>(); 252 res.addAll(cats); 253 Collections.sort(res); 254 return res; 255 } 256 257 // widget types 258 259 public void registerWidgetType(String category, WidgetTypeDefinition desc) { 260 String name = desc.getName(); 261 String className = desc.getHandlerClassName(); 262 Class<?> widgetTypeClass = null; 263 if (className != null) { 264 try { 265 widgetTypeClass = LayoutStoreImpl.class.getClassLoader().loadClass(className); 266 } catch (ReflectiveOperationException e) { 267 log.error("Caught error when instantiating widget type handler", e); 268 return; 269 } 270 } 271 272 // override only if handler class was resolved correctly 273 if (widgetTypesByCat.containsKey(name) || widgetTypeDefsByCat.containsKey(name)) { 274 log.warn(String.format("Overriding definition for widget type %s", name)); 275 widgetTypesByCat.remove(name); 276 widgetTypeDefsByCat.remove(name); 277 } 278 WidgetTypeImpl widgetType = new WidgetTypeImpl(name, widgetTypeClass, desc.getProperties()); 279 widgetType.setAliases(desc.getAliases()); 280 WidgetTypeRegistry typeReg = widgetTypesByCat.get(category); 281 if (typeReg == null) { 282 typeReg = new WidgetTypeRegistry(category); 283 widgetTypesByCat.put(category, typeReg); 284 } 285 typeReg.addContribution(widgetType); 286 WidgetTypeDefinitionRegistry defReg = widgetTypeDefsByCat.get(category); 287 if (defReg == null) { 288 defReg = new WidgetTypeDefinitionRegistry(category); 289 widgetTypeDefsByCat.put(category, defReg); 290 } 291 defReg.addContribution(desc); 292 log.info(String.format("Registered widget type '%s' for category '%s' ", name, category)); 293 } 294 295 public void unregisterWidgetType(String category, WidgetTypeDefinition desc) { 296 String name = desc.getName(); 297 WidgetTypeRegistry typeReg = widgetTypesByCat.get(category); 298 WidgetTypeDefinitionRegistry defReg = widgetTypeDefsByCat.get(category); 299 if (typeReg != null && defReg != null) { 300 // remove corresponding widget type, only reuse name 301 WidgetType widgetType = new WidgetTypeImpl(name, null, null); 302 typeReg.removeContribution(widgetType); 303 defReg.removeContribution(desc); 304 log.info(String.format("Unregistered widget type '%s' for category '%s' ", name, category)); 305 } 306 } 307 308 // layout types 309 310 public void registerLayoutType(String category, LayoutTypeDefinition layoutTypeDef) { 311 LayoutTypeDefinitionRegistry reg = layoutTypeDefsByCat.get(category); 312 if (reg == null) { 313 reg = new LayoutTypeDefinitionRegistry(category); 314 layoutTypeDefsByCat.put(category, reg); 315 } 316 reg.addContribution(layoutTypeDef); 317 log.info(String.format("Registered layout type '%s' for category '%s' ", layoutTypeDef.getName(), category)); 318 } 319 320 public void unregisterLayoutType(String category, LayoutTypeDefinition layoutTypeDef) { 321 LayoutTypeDefinitionRegistry reg = layoutTypeDefsByCat.get(category); 322 if (reg != null) { 323 reg.removeContribution(layoutTypeDef); 324 log.info(String.format("Unregistered layout type '%s' for category '%s' ", layoutTypeDef.getName(), 325 category)); 326 } 327 } 328 329 // layouts 330 331 public void registerLayout(String category, LayoutDefinition layoutDef) { 332 LayoutDefinitionRegistry reg = layoutsByCat.get(category); 333 if (reg == null) { 334 reg = new LayoutDefinitionRegistry(category); 335 layoutsByCat.put(category, reg); 336 } 337 reg.addContribution(layoutDef); 338 log.info(String.format("Registered layout '%s' for category '%s' ", layoutDef.getName(), category)); 339 } 340 341 public void unregisterLayout(String category, LayoutDefinition layoutDef) { 342 LayoutDefinitionRegistry reg = layoutsByCat.get(category); 343 if (reg != null) { 344 reg.removeContribution(layoutDef); 345 log.info(String.format("Unregistered layout '%s' for category '%s' ", layoutDef.getName(), category)); 346 } 347 } 348 349 // widgets 350 351 public void registerWidget(String category, WidgetDefinition widgetDef) { 352 WidgetDefinitionRegistry reg = widgetsByCat.get(category); 353 if (reg == null) { 354 reg = new WidgetDefinitionRegistry(category); 355 widgetsByCat.put(category, reg); 356 } 357 reg.addContribution(widgetDef); 358 log.info(String.format("Registered widget '%s' for category '%s' ", widgetDef.getName(), category)); 359 } 360 361 public void unregisterWidget(String category, WidgetDefinition widgetDef) { 362 WidgetDefinitionRegistry reg = widgetsByCat.get(category); 363 if (reg != null) { 364 reg.removeContribution(widgetDef); 365 log.info(String.format("Unregistered widget '%s' for category '%s' ", widgetDef.getName(), category)); 366 } 367 } 368 369 // converter descriptors 370 371 public void registerLayoutConverter(String category, LayoutConverterDescriptor layoutConverter) { 372 LayoutConverterRegistry reg = layoutConvertersByCat.get(category); 373 if (reg == null) { 374 reg = new LayoutConverterRegistry(category); 375 layoutConvertersByCat.put(category, reg); 376 } 377 reg.addContribution(layoutConverter); 378 log.info(String.format("Registered layout converter '%s' for category '%s' ", layoutConverter.getName(), 379 category)); 380 } 381 382 public void unregisterLayoutConverter(String category, LayoutConverterDescriptor layoutConverter) { 383 LayoutConverterRegistry reg = layoutConvertersByCat.get(category); 384 if (reg != null) { 385 reg.removeContribution(layoutConverter); 386 log.info(String.format("Unregistered layout converter '%s' for category '%s' ", layoutConverter.getName(), 387 category)); 388 } 389 } 390 391 public void registerWidgetConverter(String category, WidgetConverterDescriptor widgetConverter) { 392 WidgetConverterRegistry reg = widgetConvertersByCat.get(category); 393 if (reg == null) { 394 reg = new WidgetConverterRegistry(category); 395 widgetConvertersByCat.put(category, reg); 396 } 397 reg.addContribution(widgetConverter); 398 log.info(String.format("Registered widget converter '%s' for category '%s' ", widgetConverter.getName(), 399 category)); 400 } 401 402 public void unregisterWidgetConverter(String category, WidgetConverterDescriptor widgetConverter) { 403 WidgetConverterRegistry reg = widgetConvertersByCat.get(category); 404 if (reg != null) { 405 reg.removeContribution(widgetConverter); 406 log.info(String.format("Unregistered widget converter '%s' for category '%s' ", widgetConverter.getName(), 407 category)); 408 } 409 } 410 411 // service api 412 413 public WidgetType getWidgetType(String category, String typeName) { 414 WidgetTypeRegistry reg = widgetTypesByCat.get(category); 415 if (reg != null) { 416 return reg.getWidgetType(typeName); 417 } 418 return null; 419 } 420 421 @Override 422 public WidgetTypeDefinition getWidgetTypeDefinition(String category, String typeName) { 423 WidgetTypeDefinitionRegistry reg = widgetTypeDefsByCat.get(category); 424 if (reg != null) { 425 return reg.getDefinition(typeName); 426 } 427 return null; 428 } 429 430 @Override 431 public List<WidgetTypeDefinition> getWidgetTypeDefinitions(String category) { 432 List<WidgetTypeDefinition> res = new ArrayList<WidgetTypeDefinition>(); 433 WidgetTypeDefinitionRegistry reg = widgetTypeDefsByCat.get(category); 434 if (reg != null) { 435 Collection<WidgetTypeDefinition> defs = reg.getDefinitions(); 436 if (defs != null) { 437 res.addAll(defs); 438 } 439 } 440 return res; 441 } 442 443 @Override 444 public LayoutTypeDefinition getLayoutTypeDefinition(String category, String typeName) { 445 LayoutTypeDefinitionRegistry reg = layoutTypeDefsByCat.get(category); 446 if (reg != null) { 447 return reg.getDefinition(typeName); 448 } 449 return null; 450 } 451 452 @Override 453 public List<LayoutTypeDefinition> getLayoutTypeDefinitions(String category) { 454 List<LayoutTypeDefinition> res = new ArrayList<LayoutTypeDefinition>(); 455 LayoutTypeDefinitionRegistry reg = layoutTypeDefsByCat.get(category); 456 if (reg != null) { 457 Collection<LayoutTypeDefinition> defs = reg.getDefinitions(); 458 if (defs != null) { 459 res.addAll(defs); 460 } 461 } 462 return res; 463 } 464 465 public LayoutDefinition getLayoutDefinition(String category, String layoutName) { 466 LayoutDefinitionRegistry reg = layoutsByCat.get(category); 467 if (reg != null) { 468 return reg.getLayoutDefinition(layoutName); 469 } 470 return null; 471 } 472 473 public List<String> getLayoutDefinitionNames(String category) { 474 LayoutDefinitionRegistry reg = layoutsByCat.get(category); 475 if (reg != null) { 476 return reg.getLayoutNames(); 477 } 478 return Collections.emptyList(); 479 } 480 481 public WidgetDefinition getWidgetDefinition(String category, String widgetName) { 482 WidgetDefinitionRegistry reg = widgetsByCat.get(category); 483 if (reg != null) { 484 return reg.getWidgetDefinition(widgetName); 485 } 486 return null; 487 } 488 489 @Override 490 public List<LayoutDefinitionConverter> getLayoutConverters(String category) { 491 List<LayoutDefinitionConverter> res = new ArrayList<LayoutDefinitionConverter>(); 492 List<String> orderedConverterNames = new ArrayList<String>(); 493 LayoutConverterRegistry reg = layoutConvertersByCat.get(category); 494 if (reg != null) { 495 List<LayoutConverterDescriptor> descs = reg.getConverters(); 496 // first sort by order 497 Collections.sort(descs); 498 // instantiate converter instances 499 for (LayoutConverterDescriptor desc : descs) { 500 Class<?> converterClass; 501 try { 502 converterClass = LayoutStoreImpl.class.getClassLoader().loadClass(desc.getConverterClassName()); 503 LayoutDefinitionConverter converter = (LayoutDefinitionConverter) converterClass.newInstance(); 504 res.add(converter); 505 orderedConverterNames.add(desc.getName()); 506 } catch (ReflectiveOperationException e) { 507 log.error("Caught error when instantiating " + "layout definition converter", e); 508 } 509 } 510 } 511 if (log.isDebugEnabled()) { 512 log.debug(String.format("Ordered layout converters for category '%s': %s", category, orderedConverterNames)); 513 } 514 return res; 515 } 516 517 @Override 518 public List<WidgetDefinitionConverter> getWidgetConverters(String category) { 519 List<WidgetDefinitionConverter> res = new ArrayList<WidgetDefinitionConverter>(); 520 List<String> orderedConverterNames = new ArrayList<String>(); 521 WidgetConverterRegistry reg = widgetConvertersByCat.get(category); 522 if (reg != null) { 523 List<WidgetConverterDescriptor> descs = reg.getConverters(); 524 // first sort by order 525 Collections.sort(descs); 526 // instantiate converter instances 527 for (WidgetConverterDescriptor desc : descs) { 528 Class<?> converterClass; 529 try { 530 converterClass = LayoutStoreImpl.class.getClassLoader().loadClass(desc.getConverterClassName()); 531 WidgetDefinitionConverter converter = (WidgetDefinitionConverter) converterClass.newInstance(); 532 res.add(converter); 533 orderedConverterNames.add(desc.getName()); 534 } catch (ReflectiveOperationException e) { 535 log.error("Caught error when instantiating " + "widget definition converter", e); 536 } 537 } 538 } 539 if (log.isDebugEnabled()) { 540 log.debug(String.format("Ordered widget converters for category '%s': %s", category, orderedConverterNames)); 541 } 542 return res; 543 } 544 545}