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