001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.ui.apps.modules.edit; 029 030import org.opencms.ade.configuration.CmsADEManager; 031import org.opencms.ade.galleries.CmsSiteSelectorOptionBuilder; 032import org.opencms.ade.galleries.shared.CmsSiteSelectorOption; 033import org.opencms.db.CmsExportPoint; 034import org.opencms.db.CmsUserSettings; 035import org.opencms.file.CmsObject; 036import org.opencms.file.CmsResource; 037import org.opencms.file.types.CmsResourceTypeFolder; 038import org.opencms.file.types.I_CmsResourceType; 039import org.opencms.i18n.CmsLocaleManager; 040import org.opencms.i18n.CmsVfsBundleManager; 041import org.opencms.jsp.util.CmsJspElFunctions; 042import org.opencms.lock.CmsLockException; 043import org.opencms.main.CmsException; 044import org.opencms.main.CmsLog; 045import org.opencms.main.OpenCms; 046import org.opencms.module.CmsModule; 047import org.opencms.module.CmsModuleDependency; 048import org.opencms.module.CmsModuleVersion; 049import org.opencms.site.CmsSite; 050import org.opencms.site.CmsSiteManagerImpl; 051import org.opencms.ui.A_CmsUI; 052import org.opencms.ui.CmsVaadinUtils; 053import org.opencms.ui.apps.Messages; 054import org.opencms.ui.apps.modules.CmsModuleApp; 055import org.opencms.ui.components.CmsAutoItemCreatingComboBox; 056import org.opencms.ui.components.CmsBasicDialog; 057import org.opencms.ui.components.CmsErrorDialog; 058import org.opencms.ui.components.CmsRemovableFormRow; 059import org.opencms.ui.components.CmsResourceInfo; 060import org.opencms.ui.components.editablegroup.CmsEditableGroup; 061import org.opencms.ui.components.editablegroup.I_CmsEditableGroupRow; 062import org.opencms.ui.util.CmsComponentField; 063import org.opencms.ui.util.CmsNullToEmptyConverter; 064import org.opencms.util.CmsFileUtil; 065import org.opencms.util.CmsStringUtil; 066import org.opencms.workplace.CmsWorkplace; 067 068import java.util.Arrays; 069import java.util.HashSet; 070import java.util.List; 071import java.util.Map; 072import java.util.Set; 073import java.util.StringTokenizer; 074import java.util.TreeMap; 075 076import org.apache.commons.logging.Log; 077 078import com.google.common.base.Predicate; 079import com.google.common.base.Supplier; 080import com.google.common.collect.Lists; 081import com.google.common.collect.Maps; 082import com.vaadin.ui.AbstractComponentContainer; 083import com.vaadin.ui.Button; 084import com.vaadin.ui.Button.ClickEvent; 085import com.vaadin.ui.Button.ClickListener; 086import com.vaadin.ui.Component; 087import com.vaadin.ui.FormLayout; 088import com.vaadin.ui.TabSheet; 089import com.vaadin.v7.data.Item; 090import com.vaadin.v7.data.Property.ValueChangeEvent; 091import com.vaadin.v7.data.Property.ValueChangeListener; 092import com.vaadin.v7.data.Validator; 093import com.vaadin.v7.data.fieldgroup.BeanFieldGroup; 094import com.vaadin.v7.data.fieldgroup.FieldGroup; 095import com.vaadin.v7.data.fieldgroup.FieldGroup.CommitException; 096import com.vaadin.v7.data.util.IndexedContainer; 097import com.vaadin.v7.ui.AbstractField; 098import com.vaadin.v7.ui.CheckBox; 099import com.vaadin.v7.ui.Field; 100import com.vaadin.v7.ui.TextArea; 101import com.vaadin.v7.ui.TextField; 102import com.vaadin.v7.ui.VerticalLayout; 103 104/** 105 * Form for editing a module.<p> 106 */ 107public class CmsEditModuleForm extends CmsBasicDialog { 108 109 /** CSS class. */ 110 public static final String COMPLEX_ROW = "o-module-complex-row"; 111 112 /** Dummy site root used to identify the 'none' select option in the module site selector. */ 113 public static final String ID_EMPTY_SITE = "!empty"; 114 115 /** Classes folder within the module. */ 116 public static final String PATH_CLASSES = "classes/"; 117 118 /** Elements folder within the module. */ 119 public static final String PATH_ELEMENTS = "elements/"; 120 121 /** The formatters folder within the module. */ 122 public static final String PATH_FORMATTERS = "formatters/"; 123 124 /** Message bundle file name suffix. */ 125 private static final String SUFFIX_BUNDLE_FILE = ".messages"; 126 127 /** Lib folder within the module. */ 128 public static final String PATH_LIB = "lib/"; 129 130 /** Resources folder within the module. */ 131 public static final String PATH_RESOURCES = "resources/"; 132 133 /** Schemas folder within the module. */ 134 public static final String PATH_SCHEMAS = "schemas/"; 135 136 /** Template folder within the module. */ 137 public static final String PATH_TEMPLATES = "templates/"; 138 139 /** Logger instance for this class. */ 140 private static final Log LOG = CmsLog.getLog(CmsEditModuleForm.class); 141 142 /** The name of the caption property for the module site selector. */ 143 private static final String PROPERTY_SITE_NAME = "name"; 144 145 /** Serial version id. */ 146 private static final long serialVersionUID = 1L; 147 148 /**I18n path. */ 149 private static final String PATH_i18n = "i18n/"; 150 151 public static final String CONFIG_FILE = ".config"; 152 153 /** Text box for the action class. */ 154 private TextField m_actionClass; 155 156 /** The text box for the author email address. */ 157 private TextField m_authorEmail; 158 159 /** Text box for the author name. */ 160 private TextField m_authorName; 161 162 /** Check box to enable / disable version autoincrement mode. */ 163 private CheckBox m_autoIncrement; 164 165 /** The cancel button. */ 166 private Button m_cancel; 167 168 /** Layout containing the module dependency widgets. */ 169 private FormLayout m_dependencies; 170 171 /** Group for editing lists of dependencies. */ 172 private CmsEditableGroup m_dependencyGroup; 173 174 /** Text box for the description. */ 175 private TextArea m_description; 176 177 /** Parent layout for the excluded resources. */ 178 private FormLayout m_excludedResources; 179 180 /** The group for the excluded module resource fields. */ 181 private CmsEditableGroup m_excludedResourcesGroup; 182 183 /** Group for editing list of export points. */ 184 private CmsEditableGroup m_exportPointGroup; 185 186 /** Parent layout for export point widgets. */ 187 private VerticalLayout m_exportPoints; 188 189 /** The field group. */ 190 private BeanFieldGroup<CmsModule> m_fieldGroup = new BeanFieldGroup<CmsModule>(CmsModule.class); 191 192 /** Check box for creating the classes folder. */ 193 private CheckBox m_folderClasses; 194 195 /** Check box for creating the elmments folder. */ 196 private CheckBox m_folderI18N; 197 198 /** Check box for creating the formatters folder. */ 199 private CheckBox m_folderFormatters; 200 201 /** Check box for creating the lib folder. */ 202 private CheckBox m_folderLib; 203 204 /** Check box for crreating the module folder. */ 205 private CheckBox m_folderModule; 206 207 /** Check box for creating the resources folder. */ 208 private CheckBox m_folderResources; 209 210 /** Check box for creating the schemas folder. */ 211 private CheckBox m_folderSchemas; 212 213 /** Check box for creating the templates folder. */ 214 private CheckBox m_folderTemplates; 215 216 /** Text box for the group. */ 217 private TextField m_group; 218 219 /** Check box to enable / disable fixed import site. */ 220 private CheckBox m_hasImportSite; 221 222 /** Text area for the import script. */ 223 private TextArea m_importScript; 224 225 /** Select box for the module site. */ 226 private CmsAutoItemCreatingComboBox m_importSite; 227 228 /** Contains the widget used to display the module site information. */ 229 private CmsComponentField<CmsResourceInfo> m_info = new CmsComponentField<CmsResourceInfo>(); 230 231 /** The module being edited. */ 232 private CmsModule m_module; 233 234 /** The layout containing the module resources. */ 235 private FormLayout m_moduleResources; 236 237 /** The group for the module resource fields. */ 238 private CmsEditableGroup m_moduleResourcesGroup; 239 240 /** Text box for the module name. */ 241 private TextField m_name; 242 243 /** True if this dialog instance was opened for a new module (rather than an existing module). */ 244 private boolean m_new; 245 246 /** Text box for the nice module name. */ 247 private TextField m_niceName; 248 249 /** The OK button. */ 250 private Button m_ok; 251 252 /** The original module instance passed into the constructor. */ 253 private CmsModule m_oldModuleInstance; 254 255 /** Group for editing lists of parameters. */ 256 private CmsEditableGroup m_parameterGroup; 257 258 /** Parent layout for module parameter widgets. */ 259 private FormLayout m_parameters; 260 261 /** Check box for the 'reduced metadata' export mode. */ 262 private CheckBox m_reducedMetadata; 263 264 /** The tab layout. */ 265 private TabSheet m_tabs; 266 267 /** The callback to call after editing the module. */ 268 private Runnable m_updateCallback; 269 270 /** Text box for the version. */ 271 private TextField m_version; 272 273 /** 274 * Creates a new instance.<p> 275 * 276 * @param module the module to edit 277 * @param newModule true if the module is a new one, false for editing an existing module 278 * @param updateCallback the update callback 279 */ 280 @SuppressWarnings("unchecked") 281 public CmsEditModuleForm(CmsModule module, boolean newModule, Runnable updateCallback) { 282 283 m_oldModuleInstance = module; 284 m_module = (module.clone()); 285 String site = m_module.getSite(); 286 if (!CmsStringUtil.isEmptyOrWhitespaceOnly(site)) { 287 site = site.trim(); 288 if (!site.equals("/")) { 289 site = CmsFileUtil.removeTrailingSeparator(site); 290 m_module.setSite(site); 291 } 292 } 293 m_new = newModule; 294 m_updateCallback = updateCallback; 295 CmsVaadinUtils.readAndLocalizeDesign(this, CmsVaadinUtils.getWpMessagesForCurrentLocale(), null); 296 IndexedContainer importSitesModel = getModuleSiteContainer( 297 A_CmsUI.getCmsObject(), 298 PROPERTY_SITE_NAME, 299 m_module.getSite()); 300 m_importSite.setContainerDataSource(importSitesModel); 301 m_importSite.setNullSelectionItemId(ID_EMPTY_SITE); 302 m_importSite.setItemCaptionPropertyId(PROPERTY_SITE_NAME); 303 m_importSite.setNewValueHandler(new CmsSiteSelectorNewValueHandler(PROPERTY_SITE_NAME)); 304 if (m_new) { 305 m_module.setCreateModuleFolder(true); 306 m_module.setCreateI18NFolder(true); 307 } 308 m_fieldGroup.setItemDataSource(m_module); 309 m_fieldGroup.bind(m_name, "name"); 310 m_fieldGroup.bind(m_niceName, "niceName"); 311 m_fieldGroup.bind(m_description, "description"); 312 m_fieldGroup.bind(m_version, "versionStr"); 313 m_fieldGroup.bind(m_group, "group"); 314 m_fieldGroup.bind(m_actionClass, "actionClass"); 315 m_fieldGroup.bind(m_importScript, "importScript"); 316 m_fieldGroup.bind(m_importSite, "site"); 317 m_fieldGroup.bind(m_hasImportSite, "hasImportSite"); 318 m_fieldGroup.bind(m_authorName, "authorName"); 319 m_fieldGroup.bind(m_authorEmail, "authorEmail"); 320 m_fieldGroup.bind(m_reducedMetadata, "reducedExportMode"); 321 m_fieldGroup.bind(m_folderModule, "createModuleFolder"); 322 m_fieldGroup.bind(m_folderClasses, "createClassesFolder"); 323 m_fieldGroup.bind(m_folderI18N, "createI18NFolder"); 324 m_fieldGroup.bind(m_folderFormatters, "createFormattersFolder"); 325 m_fieldGroup.bind(m_folderLib, "createLibFolder"); 326 m_fieldGroup.bind(m_folderResources, "createResourcesFolder"); 327 m_fieldGroup.bind(m_folderSchemas, "createSchemasFolder"); 328 m_fieldGroup.bind(m_autoIncrement, "autoIncrement"); 329 if (m_new) { 330 m_reducedMetadata.setValue(Boolean.TRUE); 331 m_name.addValidator(new Validator() { 332 333 private static final long serialVersionUID = 1L; 334 335 public void validate(Object value) throws InvalidValueException { 336 337 if (OpenCms.getModuleManager().hasModule((String)value)) { 338 throw new InvalidValueException( 339 CmsVaadinUtils.getMessageText(Messages.GUI_MODULES_MODULE_ALREADY_EXISTS_0)); 340 } 341 if (!CmsStringUtil.isValidJavaClassName((String)value)) { 342 throw new InvalidValueException( 343 CmsVaadinUtils.getMessageText(Messages.GUI_MODULES_INVALID_MODULE_NAME_0)); 344 } 345 } 346 347 }); 348 349 } 350 m_version.addValidator(new Validator() { 351 352 private static final long serialVersionUID = 1L; 353 354 public void validate(Object value) throws InvalidValueException { 355 356 try { 357 @SuppressWarnings("unused") 358 CmsModuleVersion ver = new CmsModuleVersion("" + value); 359 } catch (Exception e) { 360 throw new InvalidValueException( 361 CmsVaadinUtils.getMessageText(Messages.GUI_MODULES_INVALID_MODULE_VERSION_0)); 362 } 363 } 364 }); 365 m_fieldGroup.bind(m_folderTemplates, "createTemplateFolder"); 366 for (AbstractField<String> field : new AbstractField[] { 367 m_name, 368 m_niceName, 369 m_group, 370 m_importScript, 371 m_actionClass}) { 372 field.setConverter(new CmsNullToEmptyConverter()); 373 } 374 375 if (!newModule) { 376 for (AbstractField<?> field : new AbstractField[] { 377 m_folderModule, 378 m_folderClasses, 379 m_folderI18N, 380 m_folderFormatters, 381 m_folderLib, 382 m_folderResources, 383 m_folderSchemas, 384 m_folderTemplates}) { 385 field.setVisible(false); 386 } 387 m_name.setEnabled(false); 388 } 389 390 Supplier<Component> moduleResourceFieldFactory = new Supplier<Component>() { 391 392 public Component get() { 393 394 return createModuleResourceField(null); 395 } 396 }; 397 String addResourceButtonText = CmsVaadinUtils.getMessageText(Messages.GUI_MODULES_ADD_RESOURCE_0); 398 m_moduleResourcesGroup = new CmsEditableGroup( 399 m_moduleResources, 400 moduleResourceFieldFactory, 401 addResourceButtonText); 402 m_excludedResourcesGroup = new CmsEditableGroup( 403 m_excludedResources, 404 moduleResourceFieldFactory, 405 addResourceButtonText); 406 m_parameterGroup = new CmsEditableGroup(m_parameters, new Supplier<Component>() { 407 408 public Component get() { 409 410 TextField result = new TextField(); 411 return result; 412 } 413 }, CmsVaadinUtils.getMessageText(Messages.GUI_MODULES_ADD_PARAMETER_0)); 414 m_exportPointGroup = new CmsEditableGroup(m_exportPoints, new Supplier<Component>() { 415 416 public Component get() { 417 418 return new CmsExportPointWidget("", ""); 419 } 420 }, CmsVaadinUtils.getMessageText(Messages.GUI_MODULES_ADD_EXPORT_POINT_0)); 421 422 m_dependencyGroup = new CmsEditableGroup(m_dependencies, new Supplier<Component>() { 423 424 public Component get() { 425 426 CmsModuleDependencyWidget component = CmsModuleDependencyWidget.create(null); 427 return component; 428 } 429 }, CmsVaadinUtils.getMessageText(Messages.GUI_MODULES_ADD_DEPENDENCY_0)); 430 431 m_moduleResourcesGroup.init(); 432 m_excludedResourcesGroup.init(); 433 m_parameterGroup.init(); 434 m_exportPointGroup.init(); 435 m_dependencyGroup.init(); 436 String resourceListError = CmsVaadinUtils.getMessageText(Messages.GUI_MODULES_RESOURCE_LIST_ERROR_0); 437 m_moduleResourcesGroup.setErrorMessage(resourceListError); 438 m_excludedResourcesGroup.setErrorMessage(resourceListError); 439 440 Map<String, String> params = module.getParameters(); 441 for (Map.Entry<String, String> entry : params.entrySet()) { 442 addParameter(entry.getKey() + "=" + entry.getValue()); 443 } 444 for (CmsModuleDependency dependency : module.getDependencies()) { 445 addDependencyRow(dependency); 446 } 447 448 for (CmsExportPoint exportPoint : module.getExportPoints()) { 449 addExportPointRow(exportPoint.getUri(), exportPoint.getConfiguredDestination()); 450 } 451 for (String moduleResource : module.getResources()) { 452 addModuleResource(moduleResource); 453 } 454 455 for (String excludedResource : module.getExcludeResources()) { 456 addExcludedResource(excludedResource); 457 } 458 459 m_cancel.addClickListener(new ClickListener() { 460 461 private static final long serialVersionUID = 1L; 462 463 public void buttonClick(ClickEvent event) { 464 465 CmsVaadinUtils.getWindow(CmsEditModuleForm.this).close(); 466 } 467 }); 468 m_ok.addClickListener(new ClickListener() { 469 470 private static final long serialVersionUID = 1L; 471 472 public void buttonClick(ClickEvent event) { 473 474 updateModule(); 475 } 476 }); 477 m_importSite.addValueChangeListener(new ValueChangeListener() { 478 479 private static final long serialVersionUID = 1L; 480 481 @SuppressWarnings("synthetic-access") 482 public void valueChange(ValueChangeEvent event) { 483 484 String siteRoot = (String)(event.getProperty().getValue()); 485 updateSiteInfo(siteRoot); 486 487 } 488 }); 489 490 m_info.set(new CmsResourceInfo("", "", "")); 491 m_info.get().getResourceIcon().initContent(null, CmsModuleApp.Icons.RESINFO_ICON, null, false, false); 492 updateSiteInfo(module.getSite()); 493 displayResourceInfoDirectly(Arrays.asList(m_info.get())); 494 } 495 496 /** 497 * Builds the container used for the module site selector.<p> 498 * 499 * @param cms the CMS context 500 * @param captionPropertyName the name of the property used to store captions 501 * @param prevValue the value previously set in the module 502 * 503 * @return the container with the available sites 504 */ 505 public static IndexedContainer getModuleSiteContainer(CmsObject cms, String captionPropertyName, String prevValue) { 506 507 CmsSiteSelectorOptionBuilder optBuilder = new CmsSiteSelectorOptionBuilder(cms); 508 optBuilder.addNormalSites(true, (new CmsUserSettings(cms)).getStartFolder()); 509 IndexedContainer availableSites = new IndexedContainer(); 510 availableSites.addContainerProperty(captionPropertyName, String.class, null); 511 for (CmsSiteSelectorOption option : optBuilder.getOptions()) { 512 String siteRoot = option.getSiteRoot(); 513 if (siteRoot.equals("")) { 514 siteRoot = "/"; 515 } 516 Item siteItem = availableSites.addItem(siteRoot); 517 siteItem.getItemProperty(captionPropertyName).setValue(option.getMessage()); 518 } 519 if (!availableSites.containsId(prevValue)) { 520 String caption = prevValue; 521 String siteId = prevValue; 522 523 if (CmsStringUtil.isEmptyOrWhitespaceOnly(prevValue)) { 524 caption = CmsVaadinUtils.getMessageText(Messages.GUI_MODULES_MODULE_SITE_NONE_0); 525 siteId = ID_EMPTY_SITE; 526 } 527 availableSites.addItem(siteId).getItemProperty(captionPropertyName).setValue(caption); 528 } 529 return availableSites; 530 } 531 532 /** 533 * Adds another entry to the list of module dependencies in the dependencies tab.<p> 534 * 535 * @param dep the module dependency for which a new row should be added 536 */ 537 public void addDependencyRow(CmsModuleDependency dep) { 538 539 CmsModuleDependencyWidget w = CmsModuleDependencyWidget.create(dep); 540 m_dependencyGroup.addRow(w); 541 } 542 543 /** 544 * Adds another entry to the list of export points in the export point tab.<p> 545 * 546 * @param src the export point source 547 * @param target the export point target 548 */ 549 public void addExportPointRow(String src, String target) { 550 551 CmsExportPointWidget exportPointWidget = new CmsExportPointWidget(src, target); 552 m_exportPointGroup.addRow(exportPointWidget); 553 // row.addStyleName(COMPLEX_ROW); 554 // m_exportPoints.addComponent(row); 555 } 556 557 /** 558 * Writes the form data back to the module.<p> 559 */ 560 public void updateModule() { 561 562 try { 563 m_fieldGroup.commit(); 564 // validate 'dynamic' tabs here 565 TreeMap<String, String> params = Maps.newTreeMap(); 566 for (I_CmsEditableGroupRow row : m_parameterGroup.getRows()) { 567 TextField paramField = (TextField)(row.getComponent()); 568 String paramStr = paramField.getValue(); 569 int eqPos = paramStr.indexOf("="); 570 if (eqPos >= 0) { 571 String key = paramStr.substring(0, eqPos); 572 key = key.trim(); 573 String value = paramStr.substring(eqPos + 1); 574 value = value.trim(); 575 if (!CmsStringUtil.isEmpty(key)) { 576 params.put(key, value); 577 } 578 } 579 } 580 m_module.setParameters(params); 581 582 List<CmsExportPoint> exportPoints = Lists.newArrayList(); 583 for (I_CmsEditableGroupRow row : m_exportPointGroup.getRows()) { 584 CmsExportPointWidget widget = (CmsExportPointWidget)(row.getComponent()); 585 String source = widget.getUri().trim(); 586 String target = widget.getDestination().trim(); 587 if (CmsStringUtil.isEmpty(source) || CmsStringUtil.isEmpty(target)) { 588 continue; 589 } 590 CmsExportPoint point = new CmsExportPoint(source, target); 591 exportPoints.add(point); 592 } 593 m_module.setExportPoints(exportPoints); 594 595 List<CmsModuleDependency> dependencies = Lists.newArrayList(); 596 for (CmsModuleDependencyWidget widget : getFormRowChildren( 597 m_dependencies, 598 CmsModuleDependencyWidget.class)) { 599 String moduleName = widget.getModuleName(); 600 String moduleVersion = widget.getModuleVersion(); 601 try { 602 CmsModuleDependency dep = new CmsModuleDependency(moduleName, new CmsModuleVersion(moduleVersion)); 603 dependencies.add(dep); 604 } catch (Exception e) { 605 LOG.debug(e.getLocalizedMessage(), e); 606 } 607 } 608 m_module.setDependencies(dependencies); 609 610 List<String> moduleResources = Lists.newArrayList(); 611 for (I_CmsEditableGroupRow row : m_moduleResourcesGroup.getRows()) { 612 CmsModuleResourceSelectField field = (CmsModuleResourceSelectField)(row.getComponent()); 613 String moduleResource = field.getValue().trim(); 614 if (!moduleResource.isEmpty()) { 615 moduleResources.add(moduleResource); 616 } 617 } 618 m_module.setResources(moduleResources); 619 620 List<String> excludedResources = Lists.newArrayList(); 621 for (I_CmsEditableGroupRow row : m_excludedResourcesGroup.getRows()) { 622 CmsModuleResourceSelectField field = (CmsModuleResourceSelectField)(row.getComponent()); 623 String moduleResource = field.getValue().trim(); 624 if (!moduleResource.isEmpty()) { 625 excludedResources.add(moduleResource); 626 } 627 } 628 m_module.setExcludeResources(excludedResources); 629 630 if (!m_oldModuleInstance.isAutoIncrement() && m_module.isAutoIncrement()) { 631 m_module.setCheckpointTime(System.currentTimeMillis()); 632 } 633 634 CmsObject cms = A_CmsUI.getCmsObject(); 635 if (m_new) { 636 createModuleFolders(cms, m_module); 637 OpenCms.getModuleManager().addModule(cms, m_module); 638 } else { 639 OpenCms.getModuleManager().updateModule(cms, m_module); 640 } 641 CmsVaadinUtils.getWindow(this).close(); 642 m_updateCallback.run(); 643 } catch (CommitException e) { 644 if (e.getCause() instanceof FieldGroup.FieldGroupInvalidValueException) { 645 int minTabIdx = 999; 646 for (Field<?> field : e.getInvalidFields().keySet()) { 647 int tabIdx = getTabIndex(field); 648 if (tabIdx != -1) { 649 minTabIdx = Math.min(tabIdx, minTabIdx); 650 } 651 } 652 m_tabs.setSelectedTab(minTabIdx); 653 } else { 654 CmsErrorDialog.showErrorDialog(e); 655 } 656 return; 657 } catch (Exception e) { 658 CmsErrorDialog.showErrorDialog(e); 659 } 660 661 } 662 663 /** 664 * Adds a new module dependency widget.<p> 665 * 666 * @param moduleName the module name 667 * @param version the module version 668 */ 669 void addDependency(String moduleName, String version) { 670 671 try { 672 m_dependencies.addComponent( 673 new CmsRemovableFormRow<CmsModuleDependencyWidget>( 674 CmsModuleDependencyWidget.create( 675 new CmsModuleDependency(moduleName, new CmsModuleVersion(version))), 676 "")); 677 } catch (Exception e) { 678 CmsErrorDialog.showErrorDialog(e); 679 } 680 } 681 682 /** 683 * Adds a new resource selection widget to the list of module resources.<p> 684 * 685 * @param moduleResource the initial value for the new widget 686 */ 687 void addExcludedResource(String moduleResource) { 688 689 CmsModuleResourceSelectField resField = createModuleResourceField(moduleResource); 690 if (resField != null) { 691 m_excludedResourcesGroup.addRow(resField); 692 } 693 } 694 695 /** 696 * Adds a new module resource row.<p> 697 * 698 * @param moduleResource the initial value for the module resource 699 */ 700 void addModuleResource(String moduleResource) { 701 702 CmsModuleResourceSelectField resField = createModuleResourceField(moduleResource); 703 if (resField != null) { 704 m_moduleResourcesGroup.addRow(resField); 705 } 706 } 707 708 /** 709 * Add a given parameter to the form layout.<p> 710 * 711 * @param parameter parameter to add to form 712 */ 713 void addParameter(String parameter) { 714 715 TextField textField = new TextField(); 716 if (parameter != null) { 717 textField.setValue(parameter); 718 } 719 m_parameterGroup.addRow(textField); 720 } 721 722 /** 723 * Creates a module resource selection field.<p> 724 * 725 * @param moduleResource the initial content for the field 726 * 727 * @return the module resource selection field 728 */ 729 CmsModuleResourceSelectField createModuleResourceField(String moduleResource) { 730 731 CmsModuleResourceSelectField resField = new CmsModuleResourceSelectField(); 732 CmsObject moduleCms = null; 733 try { 734 moduleCms = OpenCms.initCmsObject(A_CmsUI.getCmsObject()); 735 if (getSelectedSite() != null) { 736 moduleCms.getRequestContext().setSiteRoot(getSelectedSite()); 737 } 738 resField.setCmsObject(moduleCms); 739 if (moduleResource != null) { 740 resField.setValue(moduleResource); 741 } 742 return resField; 743 } catch (CmsException e) { 744 LOG.error(e.getLocalizedMessage(), e); 745 return null; 746 } 747 } 748 749 /** 750 * Helper method to get the descendants of a container with a specific widget type.<p> 751 * 752 * @param container the container 753 * @param cls the class 754 * 755 * @return the list of results 756 */ 757 <T extends Component> List<T> getFormRowChildren(AbstractComponentContainer container, final Class<T> cls) { 758 759 final List<T> result = Lists.newArrayList(); 760 CmsVaadinUtils.visitDescendants(container, new Predicate<Component>() { 761 762 public boolean apply(Component comp) { 763 764 if (cls.isAssignableFrom(comp.getClass())) { 765 result.add(cls.cast(comp)); 766 } 767 return true; 768 } 769 }); 770 return result; 771 } 772 773 /** 774 * Gets the site root currently selected in the module site combo box.<p> 775 * 776 * @return the currently selected module site 777 */ 778 String getSelectedSite() { 779 780 return (String)(m_importSite.getValue()); 781 } 782 783 /** 784 * Gets the tab index for the given component.<p> 785 * 786 * @param component a component 787 * 788 * @return the tab index 789 */ 790 int getTabIndex(Component component) { 791 792 List<Component> tabs = Lists.newArrayList(m_tabs.iterator()); 793 while (component != null) { 794 int pos = tabs.indexOf(component); 795 if (pos >= 0) { 796 return pos; 797 } 798 component = component.getParent(); 799 } 800 return -1; 801 } 802 803 /** 804 * Creates all module folders that are selected in the input form.<p> 805 * 806 * @param module the module 807 * 808 * @return the updated module 809 * 810 * @throws CmsException if somehting goes wrong 811 */ 812 private CmsModule createModuleFolders(CmsObject cms, CmsModule module) throws CmsException { 813 814 String modulePath = CmsWorkplace.VFS_PATH_MODULES + module.getName() + "/"; 815 List<CmsExportPoint> exportPoints = module.getExportPoints(); 816 List<String> resources = module.getResources(); 817 818 // set the createModuleFolder flag if any other flag is set 819 if (module.isCreateClassesFolder() 820 || module.isCreateElementsFolder() 821 || module.isCreateI18NFolder() 822 || module.isCreateLibFolder() 823 || module.isCreateResourcesFolder() 824 || module.isCreateSchemasFolder() 825 || module.isCreateTemplateFolder() 826 || module.isCreateFormattersFolder()) { 827 module.setCreateModuleFolder(true); 828 } 829 830 Set<String> exportPointPaths = new HashSet<String>(); 831 for (CmsExportPoint exportPoint : exportPoints) { 832 exportPointPaths.add(exportPoint.getUri()); 833 } 834 835 // check if we have to create the module folder 836 837 I_CmsResourceType folderType = OpenCms.getResourceManager().getResourceType( 838 CmsResourceTypeFolder.getStaticTypeName()); 839 I_CmsResourceType configType = OpenCms.getResourceManager().getResourceType(CmsADEManager.MODULE_CONFIG_TYPE); 840 841 if (module.isCreateModuleFolder()) { 842 CmsResource resource = cms.createResource(modulePath, folderType); 843 CmsResource configResource = cms.createResource(modulePath + CONFIG_FILE, configType); 844 try { 845 cms.unlockResource(resource); 846 cms.unlockResource(configResource); 847 } catch (CmsLockException locke) { 848 LOG.warn("Unbale to unlock resource", locke); 849 } 850 // add the module folder to the resource list 851 resources.add(modulePath); 852 module.setResources(resources); 853 } 854 855 // check if we have to create the template folder 856 if (module.isCreateTemplateFolder()) { 857 String path = modulePath + PATH_TEMPLATES; 858 CmsResource resource = cms.createResource(path, folderType); 859 try { 860 cms.unlockResource(resource); 861 } catch (CmsLockException locke) { 862 LOG.warn("Unbale to unlock resource", locke); 863 } 864 } 865 866 if (module.isCreateI18NFolder()) { 867 String path = modulePath + PATH_i18n; 868 CmsResource resource = cms.createResource(path, folderType); 869 CmsResource bundleResource = cms.createResource( 870 path + module.getName() + SUFFIX_BUNDLE_FILE + "_" + CmsLocaleManager.getDefaultLocale(), 871 OpenCms.getResourceManager().getResourceType(CmsVfsBundleManager.TYPE_PROPERTIES_BUNDLE), 872 null, 873 null); 874 cms.writeResource(bundleResource); 875 try { 876 cms.unlockResource(resource); 877 cms.unlockResource(bundleResource); 878 } catch (CmsLockException locke) { 879 LOG.warn("Unbale to unlock resource", locke); 880 } 881 } 882 883 // check if we have to create the elements folder 884 if (module.isCreateElementsFolder()) { 885 String path = modulePath + PATH_ELEMENTS; 886 CmsResource resource = cms.createResource(path, folderType); 887 try { 888 cms.unlockResource(resource); 889 } catch (CmsLockException locke) { 890 LOG.warn("Unbale to unlock resource", locke); 891 } 892 } 893 894 if (module.isCreateFormattersFolder()) { 895 String path = modulePath + PATH_FORMATTERS; 896 CmsResource resource = cms.createResource(path, folderType); 897 try { 898 cms.unlockResource(resource); 899 } catch (CmsLockException locke) { 900 LOG.warn("Unbale to unlock resource", locke); 901 } 902 } 903 904 // check if we have to create the schemas folder 905 if (module.isCreateSchemasFolder()) { 906 String path = modulePath + PATH_SCHEMAS; 907 CmsResource resource = cms.createResource(path, folderType); 908 try { 909 cms.unlockResource(resource); 910 } catch (CmsLockException locke) { 911 LOG.warn("Unbale to unlock resource", locke); 912 } 913 } 914 915 // check if we have to create the resources folder 916 if (module.isCreateResourcesFolder()) { 917 String path = modulePath + PATH_RESOURCES; 918 CmsResource resource = cms.createResource(path, folderType); 919 try { 920 cms.unlockResource(resource); 921 } catch (CmsLockException locke) { 922 LOG.warn("Unbale to unlock resource", locke); 923 } 924 } 925 926 // check if we have to create the lib folder 927 if (module.isCreateLibFolder()) { 928 String path = modulePath + PATH_LIB; 929 CmsResource resource = cms.createResource(path, folderType); 930 try { 931 cms.unlockResource(resource); 932 } catch (CmsLockException locke) { 933 LOG.warn("Unbale to unlock resource", locke); 934 } 935 if (!exportPointPaths.contains(path)) { 936 CmsExportPoint exp = new CmsExportPoint(path, "WEB-INF/lib/"); 937 exportPoints.add(exp); 938 } 939 module.setExportPoints(exportPoints); 940 } 941 942 // check if we have to create the classes folder 943 if (module.isCreateClassesFolder()) { 944 String path = modulePath + PATH_CLASSES; 945 CmsResource resource = cms.createResource(path, folderType); 946 try { 947 cms.unlockResource(resource); 948 } catch (CmsLockException locke) { 949 LOG.warn("Unbale to unlock resource", locke); 950 } 951 if (!exportPointPaths.contains(path)) { 952 CmsExportPoint exp = new CmsExportPoint(path, "WEB-INF/classes/"); 953 exportPoints.add(exp); 954 module.setExportPoints(exportPoints); 955 } 956 957 // now create all subfolders for the package structure 958 StringTokenizer tok = new StringTokenizer(m_module.getName(), "."); 959 while (tok.hasMoreTokens()) { 960 String folder = tok.nextToken(); 961 path += folder + "/"; 962 CmsResource resource2 = cms.createResource(path, folderType); 963 try { 964 cms.unlockResource(resource2); 965 } catch (CmsLockException locke) { 966 LOG.warn("Unbale to unlock resource", locke); 967 } 968 } 969 } 970 return module; 971 } 972 973 /** 974 * Updates the module site info display after the module site is changed.<p> 975 * 976 * @param siteRoot the new module site root 977 */ 978 private void updateSiteInfo(final String siteRoot) { 979 980 String top = ""; 981 String bottom = ""; 982 983 if (m_new) { 984 top = CmsVaadinUtils.getMessageText(Messages.GUI_MODULES_RESINFO_NEW_MODULE_0); 985 } else { 986 top = m_module.getName(); 987 } 988 989 if (siteRoot == null) { 990 bottom = CmsVaadinUtils.getMessageText(Messages.GUI_MODULES_MODULE_SITE_NOT_SET_0); 991 } else { 992 CmsSiteManagerImpl siteManager = OpenCms.getSiteManager(); 993 CmsSite site = siteManager.getSiteForSiteRoot(siteRoot); 994 if (site != null) { 995 bottom = CmsVaadinUtils.getMessageText( 996 Messages.GUI_MODULES_MODULE_SITE_1, 997 site.getTitle() + " (" + siteRoot + ")"); 998 } else if (siteRoot.equals("") || siteRoot.equals("/")) { 999 bottom = CmsVaadinUtils.getMessageText(Messages.GUI_MODULES_MODULE_SITE_ROOT_FOLDER_0); 1000 } else { 1001 bottom = CmsVaadinUtils.getMessageText(Messages.GUI_MODULES_MODULE_SITE_1, siteRoot); 1002 } 1003 } 1004 m_info.get().getTopLine().setValue(top); 1005 m_info.get().getBottomLine().setValue(CmsJspElFunctions.stripHtml(bottom)); 1006 1007 for (Component c : Arrays.asList(m_moduleResources, m_excludedResources)) { 1008 CmsVaadinUtils.visitDescendants(c, new Predicate<Component>() { 1009 1010 public boolean apply(Component comp) { 1011 1012 if (comp instanceof CmsModuleResourceSelectField) { 1013 ((CmsModuleResourceSelectField)comp).updateSite(siteRoot); 1014 } 1015 return true; 1016 } 1017 }); 1018 } 1019 1020 } 1021 1022}