Java tutorial
/*************************************************************** * This file is part of the [fleXive](R) framework. * * Copyright (c) 1999-2014 * UCS - unique computing solutions gmbh (http://www.ucs.at) * All rights reserved * * The [fleXive](R) project is free software; you can redistribute * it and/or modify it under the terms of the GNU Lesser General Public * License version 2.1 or higher as published by the Free Software Foundation. * * The GNU Lesser General Public License can be found at * http://www.gnu.org/licenses/lgpl.html. * A copy is found in the textfile LGPL.txt and important notices to the * license from the author are found in LICENSE.txt distributed with * these libraries. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * For further information about UCS - unique computing solutions gmbh, * please see the company website: http://www.ucs.at * * For further information about [fleXive](R), please see the * project website: http://www.flexive.org * * * This copyright notice MUST APPEAR in all copies of the file! ***************************************************************/ package com.flexive.shared.scripting.groovy; import com.flexive.shared.CacheAdmin; import com.flexive.shared.EJBLookup; import com.flexive.shared.FxSharedUtils; import com.flexive.shared.content.FxPK; import com.flexive.shared.exceptions.FxApplicationException; import com.flexive.shared.scripting.FxScriptInfo; import com.flexive.shared.scripting.FxScriptMapping; import com.flexive.shared.scripting.FxScriptMappingEntry; import com.flexive.shared.security.ACLCategory; import com.flexive.shared.structure.*; import com.flexive.shared.structure.export.AssignmentDifferenceAnalyser; import com.flexive.shared.structure.export.StructureExporterTools; import com.flexive.shared.value.FxValue; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import static com.flexive.shared.structure.export.StructureExporterTools.DATATYPES; import static com.flexive.shared.structure.export.StructureExporterTools.DATATYPESSIMPLE; import static org.apache.commons.lang.StringUtils.isBlank; import static org.apache.commons.lang.StringUtils.stripToEmpty; /** * Tools and utilities for GroovyScriptExporter code generation * * @author Christopher Blasnik (c.blasnik@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at) */ public final class GroovyScriptExporterTools { static class Indent { static final String TAB = "\t"; static String tabs(int count) { StringBuilder b = new StringBuilder(10); for (int i = 0; i < count; i++) b.append(TAB); return b.toString(); } } /** * Enumeration of SYSTEM TYPES which can optionally be ignored */ enum IgnoreTypes { FOLDER, ROOT, IMAGE, ARTICLE, CONTACTDATA, DOCUMENTFILE } final static StringBuilder GROOVYPACKAGEIMPORTS = new StringBuilder( "import com.flexive.shared.*\nimport com.flexive.shared.interfaces.*") .append("\nimport com.flexive.shared.value.*\nimport com.flexive.shared.content.*") .append("\nimport com.flexive.shared.search.*\nimport com.flexive.shared.tree.*") .append("\nimport com.flexive.shared.workflow.*\nimport com.flexive.shared.media.*") .append("\nimport com.flexive.shared.scripting.groovy.*\nimport com.flexive.shared.structure.*") .append("\nimport com.flexive.shared.exceptions.*\nimport com.flexive.shared.scripting.*") .append("\nimport com.flexive.shared.security.*\nimport java.text.SimpleDateFormat;\n\n"); final static String SCRIPTHEADER = "def builder\n"; // init Groovy variable final static String STRUCTHEADER = "// *******************************\n// Structure Creation\n// *******************************\n\n"; final static String DEPHEADER = "// *******************************\n// (Mutual) Dependencies\n// *******************************\n\n"; final static String DELHEADER = "// *******************************\n// Delete Content / Types\n// *******************************\n\n"; final static String SCRIPTASSHEADER = "// *******************************\n// Script Assignments\n// *******************************\n\n"; public final static Log LOG = LogFactory.getLog(GroovyScriptExporterTools.class); static final String[] JAVA_KEYWORDS = { "abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package", "synchronized", "boolean", "do", "if", "private", "this", "break", "double", "implements", "protected", "throw", "byte", "else", "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", "catch", "extends", "int", "short", "try", "char", "final", "interface", "static", "void", "class", "finally", "long", "strictfp", "volatile", "const", "float", "native", "super", "while" }; final static String[] GROOVY_KEYWORDS = { "as", "def", "in", "property" }; private GroovyScriptExporterTools() { // no instantiation } /** * Iterates throught the enum IgnoreTypes * * @param typeName the type's name * @return returns true if the type is a system type */ public static boolean isSystemType(String typeName) { for (IgnoreTypes i : IgnoreTypes.values()) { if (typeName.equals(i.toString())) return true; } return false; } /** * This method generates the script code for a type * * @param type the FxType which should be exported * @param defaultsOnly use defaults only, do not analyse / script options * @param addWorkflow add the type's current workflow to the code * @return String returns the script code for a type */ public static String createType(FxType type, boolean defaultsOnly, boolean addWorkflow) { StringBuilder script = new StringBuilder(500); final int tabCount = 1; script.append("builder = new GroovyTypeBuilder()."); final String typeName = keyWordNameCheck(type.getName(), true); script.append(typeName.toLowerCase()).append("( "); // opening parenthesis + 1x \s if (!defaultsOnly) { script.append("\n"); // LABEL final long[] langs = type.getLabel().getTranslatedLanguages(); final long defLang = type.getLabel().getDefaultLanguage(); script.append("\tlabel: new FxString(true, ").append(defLang).append(", \"").append(type.getLabel()) .append("\")"); if (langs.length > 1) { // we have more than one language assignment for (long id : langs) { if (id != defLang) { script.append(".setTranslation(").append(id).append(", \"") .append(type.getLabel().getTranslation(id)).append("\")"); } } } script.append(",\n"); // sopts - a map for "simple" GroovyTypeBuilder options Map<String, String> sopts = new LinkedHashMap<String, String>(); // type acl String acl = type.getACL().getName(); // only set if different from the default structure ACL if (!CacheAdmin.getEnvironment().getACL(acl) .equals(CacheAdmin.getEnvironment().getACL(ACLCategory.STRUCTURE.getDefaultId()))) { sopts.put("acl", "\"" + acl + "\""); } // type defaultInstanceACL if (type.hasDefaultInstanceACL()) { String defInstACL = type.getDefaultInstanceACL().getName(); sopts.put("defaultInstanceACL", "\"" + defInstACL + "\""); } sopts.put("languageMode", type.getLanguage() == LanguageMode.Multiple ? "LanguageMode.Multiple" : "LanguageMode.Single"); sopts.put("trackHistory", type.isTrackHistory() + ""); if (type.isTrackHistory()) sopts.put("historyAge", type.getHistoryAge() + "L"); sopts.put("typeMode", "TypeMode." + type.getMode().name() + ""); // sopts.put("workFlow", ",\n") /* Left out for now, also needs to be added in GroovyTypeBuilder */ sopts.put("maxVersions", type.getMaxVersions() + "L"); sopts.put("storageMode", "TypeStorageMode." + type.getStorageMode().name() + ""); // not supported in FxTypeEdit, needs to be added to groovy builder sopts.put("useInstancePermissions", type.isUseInstancePermissions() + ""); sopts.put("usePropertyPermissions", type.isUsePropertyPermissions() + ""); sopts.put("useStepPermissions", type.isUseStepPermissions() + ""); sopts.put("useTypePermissions", type.isUseTypePermissions() + ""); sopts.put("usePermissions", type.isUsePermissions() + ""); if (addWorkflow) { sopts.put("workflow", "\"" + type.getWorkflow().getName() + "\""); } if (type.isDerived()) { // take out of !defaultsOnly option? // if clause necessary since rev. #2162 (all types derived from ROOT) if (!FxType.ROOT.equals(type.getParent().getName())) sopts.put("parentTypeName", "\"" + type.getParent().getName() + "\""); } // FxStructureOptions via the GroovyOptionbuilder script.append(getStructureOptions(type, tabCount)); // append options to script for (String option : sopts.keySet()) { script.append(simpleOption(option, sopts.get(option), tabCount)); } script.trimToSize(); if (script.indexOf(",\n", script.length() - 2) != -1) script.delete(script.length() - 2, script.length()); } script.append(")\n\n"); script.trimToSize(); return script.toString(); } /** * Contains the logic to generate the script code for a type's assignments * * @param type a given type * @param assignments a List of the given types immediate assignments * @param groupAssignments the Map of GroupAssignments (keys) and their child assignments (List of values) * @param defaultsOnly only use the defaults provided by the GroovyTypeBuilder * @param callOnlyGroups a List of FxGroupAssignments for which no options should be generated * @param withoutDependencies true of assignment:xpath statements should not be generated * @param differingDerivedAssignments the List of assignment ids for derived assignments differing from their base assignments * @return the script code */ public static String createTypeAssignments(FxType type, List<FxAssignment> assignments, Map<FxGroupAssignment, List<FxAssignment>> groupAssignments, boolean defaultsOnly, List<FxGroupAssignment> callOnlyGroups, boolean withoutDependencies, List<Long> differingDerivedAssignments) { // check if any of the given assignments is derived and present in the differingDerivedAssignments list boolean createTypeAssignments = false; if (assignments != null) { // at least 1 non- derived OR at least one derived assignment which is in the differingAssignments list must be found for (FxAssignment a : assignments) { if (a.isDerivedAssignment() && StructureExporterTools.getBaseTypeId(a) != type.getId()) { if ((differingDerivedAssignments != null && differingDerivedAssignments.contains(a.getId())) || !withoutDependencies) { createTypeAssignments = true; break; } } else { createTypeAssignments = true; break; } } } if ((assignments != null && assignments.size() > 0 && (createTypeAssignments || withoutDependencies)) || (callOnlyGroups != null && callOnlyGroups.size() > 0)) { final StringBuilder script = new StringBuilder(2000); script.append("builder = new GroovyTypeBuilder(\"").append(type.getName()).append("\")\n") .append("builder {\n"); // opening curly brackets // assignment walk-through final int tabCount = 1; script.append(createChildAssignments(assignments, groupAssignments, defaultsOnly, callOnlyGroups, tabCount, withoutDependencies, differingDerivedAssignments)); script.append("}\n\n"); // closing curly brackets return script.toString(); } return ""; } /** * Write the script code to create a property from a given FxPropertyAssignment * * @param pa the FxPropertyAssignment to be scripted * @param defaultsOnly use only default settings provided by the GTB, no analysis of assignments will be performed * @param tabCount the number of tabs to be added to the code's left hand side * @param withoutDependencies true = do not create assignment:xpath code * @param differingDerivedAssignments the List of assignment ids for derived assignments differing from their base assignments * @return returns the partial script as a StringBuilder instance */ public static String createProperty(FxPropertyAssignment pa, boolean defaultsOnly, int tabCount, boolean withoutDependencies, List<Long> differingDerivedAssignments) { final FxProperty prop = pa.getProperty(); StringBuilder script = new StringBuilder(1000); // NAME script.append(Indent.tabs(tabCount)); tabCount++; final String propName = keyWordNameCheck(prop.getName().toLowerCase(), true); script.append(propName).append("( "); // opening parenthesis + 1x \s if (!defaultsOnly) { script.append("\n"); // label and hint script.append(getLabelAndHintStructure(prop, true, true, tabCount)); final String dataType = prop.getDataType() + ""; // sopts - a map for "simple" GroovyTypeBuilder options Map<String, String> sopts = new LinkedHashMap<String, String>(); // ALIAS --> set if different from name if (!prop.getName().equals(pa.getAlias())) { sopts.put("alias", "\"" + pa.getAlias() + "\""); } // def multiplicity for the assignment sopts.put("defaultMultiplicity", pa.getDefaultMultiplicity() + ""); sopts.put("multilang", prop.isMultiLang() + ""); sopts.put("dataType", "FxDataType." + dataType + ""); sopts.put("acl", "CacheAdmin.getEnvironment().getACL(ACLCategory." + prop.getACL().getCategory() + ".getDefaultId())"); sopts.put("multiplicity", "new FxMultiplicity(" + prop.getMultiplicity().getMin() + "," + prop.getMultiplicity().getMax() + ")"); sopts.put("overrideACL", prop.mayOverrideACL() + ""); sopts.put("overrideMultiplicity", prop.mayOverrideBaseMultiplicity() + ""); if (prop.hasOption(FxStructureOption.OPTION_SHOW_OVERVIEW)) sopts.put("overrideInOverview", prop.mayOverrideInOverview() + ""); if (prop.hasOption(FxStructureOption.OPTION_MAXLENGTH)) sopts.put("overrideMaxLength", prop.mayOverrideMaxLength() + ""); if (prop.hasOption(FxStructureOption.OPTION_MULTILINE)) sopts.put("overrideMultiline", prop.mayOverrideMultiLine() + ""); if (prop.hasOption(FxStructureOption.OPTION_SEARCHABLE)) sopts.put("overrideSearchable", prop.mayOverrideSearchable() + ""); if (prop.hasOption(FxStructureOption.OPTION_HTML_EDITOR)) sopts.put("overrideUseHtmlEditor", prop.mayOverrideUseHTMLEditor() + ""); if (prop.hasOption(FxStructureOption.OPTION_MULTILANG)) sopts.put("overrideMultilang", prop.mayOverrideMultiLang() + ""); if (prop.getMaxLength() != 0) {// means that maxLength is not set sopts.put("maxLength", prop.getMaxLength() + ""); } sopts.put("searchable", prop.isSearchable() + ""); sopts.put("fullTextIndexed", prop.isFulltextIndexed() + ""); sopts.put("multiline", prop.isMultiLine() + ""); sopts.put("inOverview", prop.isInOverview() + ""); sopts.put("useHtmlEditor", prop.isUseHTMLEditor() + ""); sopts.put("uniqueMode", "UniqueMode." + prop.getUniqueMode()); sopts.put("enabled", pa.isEnabled() + ""); // REFERENCE if ("Reference".equals(dataType)) { final String refType = "CacheAdmin.getEnvironment().getType(\"" + prop.getReferencedType().getName() + "\")"; sopts.put("referencedType", refType + ""); } if (prop.getReferencedList() != null) { final String refList = "CacheAdmin.getEnvironment().getSelectList(\"" + prop.getReferencedList().getName() + "\")"; sopts.put("referencedList", refList + ""); } // FxStructureOptions via the GroovyOptionbuilder script.append(getStructureOptions(prop, tabCount)); // DEFAULT VALUES if (prop.isDefaultValueSet()) { final FxValue val = prop.getDefaultValue(); String defaultValue = val.toString(); StringBuilder out = new StringBuilder(100); final String multiLang = prop.isMultiLang() + ""; if (DATATYPES.contains(dataType)) { // SELECT LIST DATATYPES if ("SelectOne".equals(dataType) || "SelectMany".equals(dataType)) { final String refListName = "CacheAdmin.getEnvironment().getSelectList(\"" + prop.getReferencedList().getName(); sopts.put("referencedList", refListName + "\"),\n"); final FxSelectList list = prop.getReferencedList(); if ("SelectOne".equals(dataType)) { for (FxSelectListItem item : list.getItems()) { if (defaultValue.equals(item.getLabel().toString())) { defaultValue = item.getName(); // reassign } } out.append("new FxSelectOne(").append(multiLang) .append(", CacheAdmin.getEnvironment().getSelectListItem(").append(refListName) .append("\"), \"").append(defaultValue).append("\"))"); } else if ("SelectMany".equals(dataType)) { String[] defaults = FxSharedUtils.splitLiterals(defaultValue); for (int i = 0; i < defaults.length; i++) { for (FxSelectListItem item : list.getItems()) { if (defaults[i].equals(item.getLabel().toString())) { defaults[i] = item.getName(); // reassign } } } out.append("new FxSelectMany(").append(multiLang).append(", new SelectMany(") .append(refListName).append("\"))"); // traverse renamed defaults and append them to the script for (String d : defaults) { out.append(".selectItem(CacheAdmin.getEnvironment().getSelectListItem(") .append(refListName).append("\"), \"").append(d).append("\"))"); } out.append(")"); } } else if ("Date".equals(dataType) || "DateTime".equals(dataType) || "DateRange".equals(dataType) || "DateTimeRange".equals(dataType)) { final String df = "\"MMM dd, yyyy\""; final String dtf = "\"MMM dd, yyyy h:mm:ss a\""; if ("Date".equals(dataType)) { out.append("new FxDate(").append(multiLang).append(", new SimpleDateFormat(").append(df) .append(").parse(\"").append(defaultValue).append("\"))"); } else if ("DateTime".equals(dataType)) { out.append("new FxDateTime(").append(multiLang).append(", new SimpleDateFormat(") .append(dtf).append(").parse(\"").append(defaultValue).append("\"))"); } else if ("DateRange".equals(dataType)) { final String lower = stripToEmpty(defaultValue.substring(0, defaultValue.indexOf("-"))); final String upper = stripToEmpty( defaultValue.substring(defaultValue.indexOf("-") + 1)); out.append("new FxDateRange(").append(multiLang) .append(", new DateRange(new SimpleDateFormat(").append(df).append(").parse(\"") .append(lower).append("\"), new SimpleDateFormat(").append(df) .append(").parse(\"").append(upper).append("\")))"); } else if ("DateTimeRange".equals(dataType)) { final String lower = stripToEmpty(defaultValue.substring(0, defaultValue.indexOf("-"))); final String upper = stripToEmpty( defaultValue.substring(defaultValue.indexOf("-") + 1)); out.append("new FxDateTimeRange(").append(multiLang) .append(", new DateRange(new SimpleDateFormat(").append(dtf) .append(").parse(\"").append(lower).append("\"), new SimpleDateFormat(") .append(dtf).append(").parse(\"").append(upper).append("\")))"); } } else if ("Reference".equals(dataType)) { final FxPK pk = FxPK.fromString(defaultValue); out.append("new FxReference(").append(multiLang).append(", new ReferencedContent(") .append(pk.getId()).append(", ").append(pk.getVersion()).append("))"); } else if ("InlineReference".equals(dataType)) { // ignore for now, doesn't work properly as of yet } else if ("Binary".equals(dataType)) { // uses a new BinaryDescriptor( .. ) } } // "SIMPLE" dataTYPES if (DATATYPESSIMPLE.keySet().contains(dataType)) { for (String d : DATATYPESSIMPLE.keySet()) { if (d.equals(dataType)) { out.append(DATATYPESSIMPLE.get(d)).append("(").append(multiLang).append(", "); if (d.equals("Float") || d.equals("Double") || d.equals("LargeNumber") || d.equals("Boolean")) { out.append(defaultValue); } else { out.append("\"").append(defaultValue).append("\""); } out.append(")"); } } } out.trimToSize(); // add the computed value to the "simpleOtions" sopts.put("defaultValue", out.toString() + ","); } // append options to script for (String option : sopts.keySet()) { script.append(simpleOption(option, sopts.get(option), tabCount)); } script.trimToSize(); if (script.indexOf(",\n", script.length() - 2) != -1) script.delete(script.length() - 2, script.length()); if (script.indexOf(",", script.length() - 1) != -1) script.delete(script.length() - 1, script.length()); } script.append(")\n"); // closing parenthesis // if the difference analyser yields any data, change the assignment in the next line (only launch if defaultsOnly = false) if (!defaultsOnly) { final List<String> differences = AssignmentDifferenceAnalyser.analyse(pa, false); if (differences.size() > 0) { script.append(updatePropertyAssignment(pa, false, differences, defaultsOnly, --tabCount, withoutDependencies, differingDerivedAssignments)); } } script.trimToSize(); return script.toString(); } /** * Write the script code to update a property assignment, or to create a derived assignment * <p/> * "acl", "defaultValue", "hint", "label", "multilang", "multiline", "multiplicity" * * @param pa the FxPropertyAssignment to be updated * @param isDerived the Assignment is derived * @param differences the List of differences (map keys f. the builder) * @param defaultsOnly use only default settings provided by the GTB, no analysis of assignments will be performed * @param tabCount the number of tabs to be added to the code's left hand side * @param withoutDependencies true = do not create assignment:xPath code * @param differingDerivedAssignments the List of assignment ids for derived assignments differing from their base assignments * @return returns the partial script as a StringBuilder instance */ public static String updatePropertyAssignment(FxPropertyAssignment pa, boolean isDerived, List<String> differences, boolean defaultsOnly, int tabCount, boolean withoutDependencies, List<Long> differingDerivedAssignments) { StringBuilder script = new StringBuilder(500); final FxProperty prop = pa.getProperty(); final String dataType = pa.getProperty().getDataType() + ""; // use the alias as the reference name script.append(Indent.tabs(tabCount)); boolean createProp = false; if (!isDerived || (isDerived && differingDerivedAssignments != null && !differingDerivedAssignments.contains(pa.getId())) || (isDerived && differences.size() > 0) || (isDerived && !withoutDependencies)) createProp = true; if (createProp) { final String propAlias = keyWordNameCheck(pa.getAlias().toLowerCase(), true); script.append(propAlias).append("( "); // opening parenthesis + 1x \s } // ASSIGNMENT if (isDerived && !withoutDependencies || (isDerived && !withoutDependencies && differingDerivedAssignments != null && !differingDerivedAssignments.contains(pa.getId()))) { final String assignmentPath = CacheAdmin.getEnvironment().getAssignment(pa.getBaseAssignmentId()) .getXPath(); script.append("assignment: \"").append(assignmentPath).append("\","); } if (!defaultsOnly && differences.size() > 0) { tabCount++; script.append("\n"); // label and hint if (differences.contains("hint") || differences.contains("label")) script.append(getLabelAndHintAssignment(pa, differences.contains("label"), differences.contains("hint"), tabCount)); // sopts - a map for "simple" GroovyTypeBuilder options Map<String, String> sopts = new LinkedHashMap<String, String>(); final String multiLang = pa.isMultiLang() + ""; if (differences.contains("multilang")) { if (prop.mayOverrideMultiLang()) { sopts.put("multilang", multiLang + ""); } } if (differences.contains("acl")) { if (prop.mayOverrideACL()) sopts.put("acl", "CacheAdmin.getEnvironment().getACL(ACLCategory." + pa.getACL().getCategory() + ".getDefaultId())"); } if (differences.contains("multiplicity")) { if (prop.mayOverrideBaseMultiplicity()) sopts.put("multiplicity", "new FxMultiplicity(" + pa.getMultiplicity().getMin() + "," + pa.getMultiplicity().getMax() + ")"); } if (differences.contains("maxLength")) { if (prop.mayOverrideMaxLength()) sopts.put("maxLength", pa.getMaxLength() + ""); } if (differences.contains("inOverview")) { if (prop.mayOverrideInOverview()) sopts.put("inOverview", pa.isInOverview() + ""); } if (differences.contains("useHtmlEditor")) { if (prop.mayOverrideUseHTMLEditor()) sopts.put("useHtmlEditor", pa.isUseHTMLEditor() + ""); } if (differences.contains("multilang")) { if (pa.isMultiLang()) { sopts.put("", pa.getDefaultLanguage() + ""); } } if (differences.contains("multiline")) { if (prop.mayOverrideMultiLine()) sopts.put("multiline", pa.isMultiLine() + ""); } // FxStructureOptions via the GroovyOptionbuilder if (differences.contains("structureoptions")) script.append(getStructureOptions(pa, tabCount)); if (differences.contains("searchable")) { if (prop.mayOverrideSearchable()) sopts.put("searchable", pa.isSearchable() + ""); } // options valid for derived assignments only ********************** if (differences.contains("defaultMultiplicity")) sopts.put("defaultMultiplicity", pa.getDefaultMultiplicity() + ""); if (differences.contains("alias")) sopts.put("alias", "\"" + pa.getAlias() + "\""); if (differences.contains("enabled")) sopts.put("enabled", pa.isEnabled() + ""); if (differences.contains("defaultLanguage")) sopts.put("defaultLanguage", pa.getDefaultLanguage() + "L"); // ***************************************************************** // DEFAULT VALUES if (differences.contains("defaultValue")) { if (pa.getDefaultValue() != null) { final FxValue val = pa.getDefaultValue(); String defaultValue = val.toString(); StringBuilder out = new StringBuilder(100); if (DATATYPES.contains(dataType)) { // SELECT LIST DATATYPES if ("SelectOne".equals(dataType) || "SelectMany".equals(dataType)) { final FxSelectList list = pa.getProperty().getReferencedList(); final String refListName = "CacheAdmin.getEnvironment().getSelectList(\"" + list.getName(); sopts.put("referencedList", refListName + "\"),\n"); if ("SelectOne".equals(dataType)) { for (FxSelectListItem item : list.getItems()) { if (defaultValue.equals(item.getLabel().toString())) { defaultValue = item.getName(); // reassign } } out.append("new FxSelectOne(").append(multiLang) .append(", CacheAdmin.getEnvironment().getSelectListItem(") .append(refListName).append("\"), \"").append(defaultValue).append("\"))"); } else if ("SelectMany".equals(dataType)) { String[] defaults = FxSharedUtils.splitLiterals(defaultValue); for (int i = 0; i < defaults.length; i++) { for (FxSelectListItem item : list.getItems()) { if (defaults[i].equals(item.getLabel().toString())) { defaults[i] = item.getName(); // reassign } } } out.append("new FxSelectMany(").append(multiLang).append(", new SelectMany(") .append(refListName).append("\"))"); // traverse renamed defaults and append them to the script for (String d : defaults) { out.append(".selectItem(CacheAdmin.getEnvironment().getSelectListItem(") .append(refListName).append("\"), \"").append(d).append("\"))"); } out.append(")"); } } else if ("Date".equals(dataType) || "DateTime".equals(dataType) || "DateRange".equals(dataType) || "DateTimeRange".equals(dataType)) { final String df = "\"MMM dd, yyyy\""; final String dtf = "\"MMM dd, yyyy h:mm:ss a\""; if ("Date".equals(dataType)) { out.append("new FxDate(").append(multiLang).append(", new SimpleDateFormat(") .append(df).append(").parse(\"").append(defaultValue).append("\"))"); } else if ("DateTime".equals(dataType)) { out.append("new FxDateTime(").append(multiLang).append(", new SimpleDateFormat(") .append(dtf).append(").parse(\"").append(defaultValue).append("\"))"); } else if ("DateRange".equals(dataType)) { final String lower = stripToEmpty( defaultValue.substring(0, defaultValue.indexOf("-"))); final String upper = stripToEmpty( defaultValue.substring(defaultValue.indexOf("-") + 1)); out.append("new FxDateRange(").append(multiLang) .append(", new DateRange(new SimpleDateFormat(").append(df) .append(").parse(\"").append(lower).append("\"), new SimpleDateFormat(") .append(df).append(").parse(\"").append(upper).append("\")))"); } else if ("DateTimeRange".equals(dataType)) { final String lower = stripToEmpty( defaultValue.substring(0, defaultValue.indexOf("-"))); final String upper = stripToEmpty( defaultValue.substring(defaultValue.indexOf("-") + 1)); out.append("new FxDateTimeRange(").append(multiLang) .append(", new DateRange(new SimpleDateFormat(").append(dtf) .append(").parse(\"").append(lower).append("\"), new SimpleDateFormat(") .append(dtf).append(").parse(\"").append(upper).append("\")))"); } } else if ("Reference".equals(dataType)) { final FxPK pk = FxPK.fromString(defaultValue); out.append("new FxReference(").append(multiLang).append(", new ReferencedContent(") .append(pk.getId()).append(", ").append(pk.getVersion()).append("))"); } else if ("InlineReference".equals(dataType)) { // ignore for now, doesn't work paerly as of yet } else if ("Binary".equals(dataType)) { // TODO: impl! // uses a new BinaryDescriptor( .. ) } } // "SIMPLE" dataTYPES if (DATATYPESSIMPLE.keySet().contains(dataType)) { for (String d : DATATYPESSIMPLE.keySet()) { if (d.equals(dataType)) { out.append(DATATYPESSIMPLE.get(d)).append("(").append(multiLang).append(", "); if (d.equals("Float") || d.equals("Double") || d.equals("LargeNumber") || d.equals("Boolean")) { out.append(defaultValue); } else { out.append("\"").append(defaultValue).append("\""); } out.append(")"); } } } out.trimToSize(); sopts.put("defaultValue", out.toString() + ","); } } // append options to script if (sopts.size() > 0) { for (String option : sopts.keySet()) { script.append(simpleOption(option, sopts.get(option), tabCount)); } } script.trimToSize(); if (script.indexOf(",\n", script.length() - 2) != -1) script.delete(script.length() - 2, script.length()); } script.trimToSize(); if (script.indexOf(",", script.length() - 1) != -1) // remove last "," if written script.delete(script.length() - 1, script.length()); if (createProp) script.append(")\n"); // closing parenthesis return script.toString(); } /** * A method for setting simple GroovyTypeBuilder options * with a trailing CR * * @param option The name of the option, e.g. "searchable" * @param value the value of the option, e.g. "true" * @param tabCount the number of tabs to be added to the code's left hand side * @return returns the partial script as a StringBuilder instance */ private static StringBuilder simpleOption(String option, String value, int tabCount) { StringBuilder s = new StringBuilder(500); s.append(Indent.tabs(tabCount)).append(option).append(": ").append(value).append(",\n"); s.trimToSize(); return s; } /** * Write the script code to create a group * * @param ga the FxGroupAssignment to be scripted * @param childAssignments a List of child assignments for the given group * @param groupAssignments the map of FxGroupAssignments (keys) and their respective Lists of FxAssignments (values) * @param isDerived set to "true" if the assignment to be written is derived from another property * @param defaultsOnly use only default settings provided by the GTB, no analysis of assignments will be performed * @param callOnlyGroups a List of FxGroupAssignments for which no options should be generated * @param tabCount the number of tabs to be added to the code's left hand side * @param withoutDependencies true = do not create assignment:xpath code * @param differingDerivedAssignments the List of assignment ids for derived assignments differing from their base assignments * @return returns the partial script as a String */ public static String createGroup(FxGroupAssignment ga, List<FxAssignment> childAssignments, Map<FxGroupAssignment, List<FxAssignment>> groupAssignments, boolean isDerived, boolean defaultsOnly, List<FxGroupAssignment> callOnlyGroups, int tabCount, boolean withoutDependencies, List<Long> differingDerivedAssignments) { final StringBuilder script = new StringBuilder(200); if (!isDerived || withoutDependencies) { final FxGroup group = ga.getGroup(); // NAME script.append(Indent.tabs(tabCount)); final String groupName = keyWordNameCheck(group.getName().toUpperCase(), true); script.append(groupName).append("( "); // opening parenthesis + 1x \s // CHECK IF THIS GROUP WAS CREATED BEFOREHAND AND ONLY NEEDS TO BE CALLED FOR STRUCTURE CREATION if (callOnlyGroups == null || (callOnlyGroups != null && !callOnlyGroups.contains(ga))) { if (!defaultsOnly) { tabCount++; // add tabs for options script.append("\n"); // label and hint script.append(getLabelAndHintStructure(group, true, true, tabCount)); Map<String, String> sopts = new LinkedHashMap<String, String>(); sopts.put("alias", "\"" + ga.getAlias() + "\""); sopts.put("defaultMultiplicity", ga.getDefaultMultiplicity() + ""); sopts.put("overrideMultiplicity", group.mayOverrideBaseMultiplicity() + ""); sopts.put("multiplicity", "new FxMultiplicity(" + group.getMultiplicity().getMin() + "," + group.getMultiplicity().getMax() + ")"); sopts.put("groupMode", "GroupMode." + ga.getMode().name()); // FxStructureOptions via the GroovyOptionbuilder script.append(getStructureOptions(group, tabCount)); // append options to script for (String option : sopts.keySet()) { script.append(simpleOption(option, sopts.get(option), tabCount)); } script.trimToSize(); if (script.indexOf(",\n", script.length() - 2) != -1) script.delete(script.length() - 2, script.length()); --tabCount; // remove tab again } } script.append(") "); // closing parenthesis + 1x \s // if the difference analyser yields any data, change the assignment in the next line (only launch if defaultsOnly = false) if (!defaultsOnly) { final List<String> differences = AssignmentDifferenceAnalyser.analyse(ga, false); if (differences.size() > 0) { script.append(updateGroupAssignment(ga, false, differences, defaultsOnly, tabCount, withoutDependencies, differingDerivedAssignments)); } } } else { // DERIVED GROUP ASSIGNMENTS final List<String> differences = AssignmentDifferenceAnalyser.analyse(ga, true); script.append(updateGroupAssignment(ga, true, differences, defaultsOnly, tabCount, withoutDependencies, differingDerivedAssignments)); } // add child assignments ****************************** if (childAssignments != null && childAssignments.size() > 0) { script.append("{\n"); // closing parenthesis and curly bracket // if childAssignments != null && size() == 0, then we are calling for derived groups in derived types // --> remove current group from groupAssignments to avoid infinite recursions if (differingDerivedAssignments != null && differingDerivedAssignments.size() > 0) { groupAssignments.remove(ga); } script.append(createChildAssignments(childAssignments, groupAssignments, defaultsOnly, callOnlyGroups, ++tabCount, withoutDependencies, differingDerivedAssignments)); script.append(Indent.tabs(--tabCount)); script.append("}"); // closing curly bracket } script.append("\n"); script.trimToSize(); return script.toString(); } /** * Write the script code to create a group assignment * * @param ga the FxGroupAssignment to be scripted * @param isDerived the Assignment is derived * @param differences the List of differences (map keys f. the builder) * @param defaultsOnly use only default settings provided by the GTB, no analysis of assignments will be performed * @param tabCount the number of tabs to be added to the code's left hand side * @param withoutDependencies true = do not create assignment:xpath code * @param differingDerivedAssignments the List of assignment ids for derived assignments differing from their base assignments * @return returns the partial script as a String */ public static String updateGroupAssignment(FxGroupAssignment ga, boolean isDerived, List<String> differences, boolean defaultsOnly, int tabCount, boolean withoutDependencies, List<Long> differingDerivedAssignments) { StringBuilder script = new StringBuilder(200); final FxGroup group = ga.getGroup(); // name = alias script.append(Indent.tabs(tabCount)); boolean createGroup = false; if (!isDerived || (isDerived && differingDerivedAssignments != null && !differingDerivedAssignments.contains(ga.getId())) || (isDerived && differences.size() > 0) || (isDerived && !withoutDependencies)) createGroup = true; if (createGroup) { // script.append("\n"); final String groupAlias = keyWordNameCheck(ga.getAlias().toUpperCase(), true); script.append(groupAlias).append("( "); // opening parenthesis + 1x \s } // ASSIGNMENT if (isDerived && !withoutDependencies || (isDerived && !withoutDependencies && differingDerivedAssignments != null && !differingDerivedAssignments.contains(ga.getId()))) { final String assignmentPath = CacheAdmin.getEnvironment().getAssignment(ga.getBaseAssignmentId()) .getXPath(); script.append("assignment: \"").append(assignmentPath).append("\","); } if (!defaultsOnly && differences.size() > 0) { tabCount++; script.append("\n"); // label and hint if (differences.contains("hint") || differences.contains("label")) script.append(getLabelAndHintStructure(group, differences.contains("label"), differences.contains("hint"), tabCount)); Map<String, String> sopts = new LinkedHashMap<String, String>(); if (differences.contains("defaultMultiplicity")) sopts.put("defaultMultiplicity", ga.getDefaultMultiplicity() + ""); if (differences.contains("multiplicity")) { if (group.mayOverrideBaseMultiplicity()) sopts.put("multiplicity", "new FxMultiplicity(" + ga.getMultiplicity().getMin() + "," + ga.getMultiplicity().getMax() + ")"); } if (differences.contains("groupMode")) sopts.put("groupMode", "GroupMode." + ga.getMode().name()); if (differences.contains("enabled")) sopts.put("enabled", ga.isEnabled() + ""); // FxStructureOptions via the GroovyOptionbuilder if (differences.contains("structureoptions")) script.append(getStructureOptions(ga, tabCount)); // append options to script for (String option : sopts.keySet()) { script.append(simpleOption(option, sopts.get(option), tabCount)); } script.trimToSize(); if (script.indexOf(",\n", script.length() - 2) != -1) script.delete(script.length() - 2, script.length()); } script.trimToSize(); if (script.indexOf(",", script.length() - 1) != -1) script.delete(script.length() - 1, script.length()); if (createGroup) script.append(") "); // closing parenthesis + 1x \s return script.toString(); } /** * This method is used to "route" the given child assignments to their respective evaluation methods * The method's first call comes from #generateTypeAssignments" * This method is subsequently called from #createGroup * * @param childAssignments the List of FxAssignments (children of a given group) * @param groupAssignments the map of FxGroupAssignments (keys) and their respective Lists of FxAssignments (values) * @param defaultsOnly use only default settings provided by the GTB, no analysis of assignments will be performed * @param callOnlyGroups a List of FxGroupAssignments for which no options should be generated * @param tabCount the number of tabs to be added to the code's left hand side * @param withoutDependencies true = do not create assignment:xpath code * @param differingDerivedAssignments the List of assignment ids for derived assignments differing from their base assignments * @return returns the script code or an empty String if the childassigments list is empty */ public static String createChildAssignments(List<FxAssignment> childAssignments, Map<FxGroupAssignment, List<FxAssignment>> groupAssignments, boolean defaultsOnly, List<FxGroupAssignment> callOnlyGroups, int tabCount, boolean withoutDependencies, List<Long> differingDerivedAssignments) { final StringBuilder script = new StringBuilder(2000); // "ordinary assignments" if (childAssignments != null && childAssignments.size() > 0) { for (FxAssignment a : childAssignments) { final boolean isDerived = a.isDerivedAssignment(); // PROPERTIES if (a instanceof FxPropertyAssignment) { if (isDerived && !withoutDependencies) { final List<String> differences = AssignmentDifferenceAnalyser.analyse(a, true); script.append(updatePropertyAssignment((FxPropertyAssignment) a, true, differences, defaultsOnly, tabCount, withoutDependencies, differingDerivedAssignments)); } else { script.append(createProperty((FxPropertyAssignment) a, defaultsOnly, tabCount, withoutDependencies, differingDerivedAssignments)); } // GROUPS } else if (a instanceof FxGroupAssignment) { // retrieve the child assignments for the given group and pass them on @SuppressWarnings({ "SuspiciousMethodCalls" }) final List<FxAssignment> currentChildren = groupAssignments.get(a); script.append(createGroup((FxGroupAssignment) a, currentChildren, groupAssignments, isDerived, defaultsOnly, callOnlyGroups, tabCount, withoutDependencies, differingDerivedAssignments)); } } } // changed assignmnets within (derived) groups OF DERIVED types if (childAssignments != null && childAssignments.size() == 0 && groupAssignments != null && groupAssignments.size() > 0 && differingDerivedAssignments != null && differingDerivedAssignments.size() > 0) { for (FxGroupAssignment ga : groupAssignments.keySet()) { final boolean isDerived = ga.isDerivedAssignment(); final List<FxAssignment> currentChildren = groupAssignments.get(ga); script.append(createGroup(ga, currentChildren, groupAssignments, isDerived, defaultsOnly, callOnlyGroups, tabCount, withoutDependencies, differingDerivedAssignments)); } } script.trimToSize(); return script.toString(); } /** * Retrieves the label and the hint of an FxAssignment (and the available translations) * * @param a the FxAssignment * @param label set to true to generate the label code * @param hint set to true to generate the hint code * @param tabCount the number of tabs to be added to the code's left hand side * @return returns the partial Groovy Script as a StringBuilder instance */ private static <T extends FxAssignment> StringBuilder getLabelAndHintAssignment(T a, boolean label, boolean hint, int tabCount) { StringBuilder script = new StringBuilder(200); // LABEL long[] langs = a.getLabel().getTranslatedLanguages(); long defLang = a.getLabel().getDefaultLanguage(); if (label) { script.append(Indent.tabs(tabCount)); script.append("label: new FxString(true, ") // label and hint are always multilang .append(defLang).append(", \"").append(a.getLabel()).append("\")"); if (langs.length > 1) { // we have more than one language assignment for (long id : langs) { if (id != defLang) { script.append(".setTranslation(").append(id).append(", \"") .append(a.getLabel().getTranslation(id)).append("\")"); } } } script.append(",\n"); } // HINT if (hint) { langs = a.getHint().getTranslatedLanguages(); defLang = a.getHint().getDefaultLanguage(); String hintAsString = a.getHint().toString(); if (isBlank(hintAsString) || "null".equals(hintAsString)) hintAsString = ""; script.append(Indent.tabs(tabCount)); script.append("hint: new FxString(true, "); script.append(defLang).append(", \"").append(hintAsString).append("\")"); if (langs.length > 1) { // we have more than one language assignment for (long id : langs) { if (id != defLang) { hintAsString = a.getHint().getTranslation(id); if (isBlank(hintAsString) || "null".equals(hintAsString)) hintAsString = ""; script.append(".setTranslation(").append(id).append(", \"").append(hintAsString) .append("\")"); } } } script.append(",\n"); } script.trimToSize(); return script; } /** * Retrieves the label and the hint of a property or group (and the available translations) * * @param a the FxAssignment * @param label set to true to generate the label code * @param hint set to true to generate the hint code * @param tabCount the number of tabs to be added to the code's left hand side * @return returns the partial Groovy Script as a StringBuilder instance */ private static <T extends FxStructureElement> StringBuilder getLabelAndHintStructure(T a, boolean label, boolean hint, int tabCount) { StringBuilder script = new StringBuilder(200); // LABEL long[] langs = a.getLabel().getTranslatedLanguages(); long defLang = a.getLabel().getDefaultLanguage(); if (label) { script.append(Indent.tabs(tabCount)); script.append("label: new FxString(true, ") // label and hint are always multilang .append(defLang).append(", \"").append(a.getLabel()).append("\")"); if (langs.length > 1) { // we have more than one language assignment for (long id : langs) { if (id != defLang) { script.append(".setTranslation(").append(id).append(", \"") .append(a.getLabel().getTranslation(id)).append("\")"); } } } script.append(",\n"); } // HINT if (hint) { langs = a.getHint().getTranslatedLanguages(); defLang = a.getHint().getDefaultLanguage(); String hintAsString = a.getHint().toString(); hintAsString = hintAsString.replaceAll("\\\"", "\\\\\""); if (isBlank(hintAsString) || "null".equals(hintAsString)) hintAsString = ""; script.append(Indent.tabs(tabCount)); script.append("hint: new FxString(true, "); script.append(defLang).append(", \"").append(hintAsString).append("\")"); if (langs.length > 1) { // we have more than one language assignment for (long id : langs) { if (id != defLang) { hintAsString = a.getHint().getTranslation(id); hintAsString = hintAsString.replaceAll("\\\"", "\\\\\""); if (isBlank(hintAsString) || "null".equals(hintAsString)) hintAsString = ""; script.append(".setTranslation(").append(id).append(", \"").append(hintAsString) .append("\")"); } } } script.append(",\n"); } script.trimToSize(); return script; } /** * Retrieve all set structure options for an FxType (or FxTypeEdit) * * @param element the FxType * @param tabCount the current tab count as an int * @return returns a Map<String, String> containing the FxStructureOption --> Value mappings */ private static <T extends FxType> String getStructureOptions(T element, int tabCount) { return buildOptions(element.getOptions(), tabCount, false); } /** * Retrieve all set structure options for an FxStructureElement * * @param element the FxStructureElement (e.g. FxGroup) * @param tabCount the current tab count as an int * @return returns a Map<String, String> containing the FxStructureOption --> Value mappings */ private static <T extends FxStructureElement> String getStructureOptions(T element, int tabCount) { // Properties and and groups (base) will always have isInherited = true for any of their options return buildOptions(element.getOptions(), tabCount, true); } /** * Retrieve all set structure options for an FxAssignment * * @param element the FxAssignment * @param tabCount the current tab count as an int * @return returns a Map<String, String> containing the FxStructureOption --> Value mappings */ private static <T extends FxAssignment> String getStructureOptions(T element, int tabCount) { return buildOptions(element.getOptions(), tabCount, false); } /** * Generates script code for FxStructureOptions using the com.flexive.shared.scripting.groovy.GroovyOptionBuilder * We have to use Groovy's Eval class (#me(String x) ) for the nested builder * * @param optList the List of FxStructureOptions * @param tabCount code layouting tab count * @param inheritedAlwaysTrue set to true if these are a type's options (getIsInherited --> different ruleset as long as isInherited not properly implemented in the AssignmentEngine) * @return the stuctureOptions GTB option as a String, nothing if the list is empty */ private static String buildOptions(List<FxStructureOption> optList, int tabCount, boolean inheritedAlwaysTrue) { if (optList != null && optList.size() > 0) { StringBuilder s = new StringBuilder(500); int size = optList.size(); s.append(Indent.tabs(tabCount + 1)).append("new GroovyOptionBuilder()."); for (int i = 0; i < size; i++) { FxStructureOption current = optList.get(i); if (i == 1) s.append(" {\n"); if (i >= 1) s.append(Indent.tabs(tabCount + 1)); s.append("\"").append(current.getKey()).append("\"(value: \"").append(current.getValue()) .append("\", overridable: ").append(current.isOverridable()).append(", isInherited: "); // option isInherited option String isInheritedVal = inheritedAlwaysTrue ? "true" : Boolean.toString(current.getIsInherited()); s.append(isInheritedVal).append(")"); if (i >= 1 && i != size - 1) s.append("\n"); if (i == size - 1 && size > 1) s.append(" }"); } s.trimToSize(); return Indent.tabs(tabCount) + "structureOptions: " + "Eval.me(\"\"\"import com.flexive.shared.scripting.groovy.*\n" + s.toString() + "\"\"\"),\n"; } return ""; } /** * Generate code to delete ALL content instances for the given types, their assignments and the types themselves * * @param types the input List of FxTypes t.b. deleted * @return the script code as a String */ public static String createDeleteCode(List<FxType> types) { final StringBuilder script = new StringBuilder(500); // generate list of type ids script.append("def te = EJBLookup.getTypeEngine()\n").append("def ce = EJBLookup.getContentEngine()\n") .append("def ae = EJBLookup.getAssignmentEngine()\n\n"); script.append("def types = ["); for (int i = 0; i < types.size(); i++) { script.append("\"").append(types.get(i).getName()).append("\""); if (i < types.size() - 1) script.append(", "); else script.append("]\n\n"); } // check if the types exist (1), remove the content instances (2), remove the types themselves (3) script.append("types.each {\n").append("\tif (CacheAdmin.getEnvironment().typeExists(it)) {\n") // (1) .append("\t\tdef t = CacheAdmin.getEnvironment().getType(it)\n").append("\t\ttry {\n") .append("\t\t\tdef pkList = ce.getPKsForType(t.getId(), false)\n").append("\t\t\tpkList.each() {\n") .append("\t\t\t\tce.remove(it)\n") // (2) .append("\t\t\t}\n").append("\t\t} catch(FxApplicationException e) {\n") .append("\t\t\treturn e.getCause().getMessage()\n\t\t}\n\n").append("\t\ttry {\n") .append("\t\t\tte.remove(t.getId())\n") // (3) .append("\t\t} catch (FxApplicationException e) {\n") .append("\t\t\tif (e instanceof FxRemoveException) {\n") .append("\t\t\t\tt.getAssignedProperties().each {\n") .append("\t\t\t\t\tae.removeAssignment(it.getId())\n").append("\t\t\t\t}\n") .append("\t\t\t\tt.getAssignedGroups().each {\n") .append("\t\t\t\t\tae.removeAssignment(it.getId())\n").append("\t\t\t\t}\n") .append("\t\t\t\tte.remove(t.getId())\n").append("\t\t\t}\n").append("\t\t}\n").append("\t}\n") .append("}\n\n"); script.trimToSize(); return script.toString(); } /** * Checks if a given input String represents a Java or Groovy keyword * * @param input the input String * @param doubleQuotes true = double quotes, false = single quotes * @return returns a quoted version of the same String if input == keyword */ private static String keyWordNameCheck(String input, boolean doubleQuotes) { if (ArrayUtils.contains(JAVA_KEYWORDS, input) || ArrayUtils.contains(GROOVY_KEYWORDS, input)) { if (doubleQuotes) return "\"" + input + "\""; return "'" + input + "'"; } return input; } /** * Generate code for the script assignment mappings * * @param typeScriptMapping the type script mapping from the StructureExporterCallback * @param assignmentScriptMapping the assignment script mapping from the StructureExporterCallback * @param scriptOverride set to true to generate script override code (overwrite script if it exists) * @return returns the Groovy code as a String */ public static String createScriptAssignments(Map<Long, Map<String, List<Long>>> typeScriptMapping, Map<Long, Map<String, List<Long>>> assignmentScriptMapping, boolean scriptOverride) { final StringBuilder script = new StringBuilder(5000); script.append("def scriptCode\n"); if (scriptOverride) { script.append( "\n// SCRIPT OVERRIDE ********\nboolean scriptOverride = true\n// ************************\n"); } // TYPE SCRIPTS if (typeScriptMapping != null && typeScriptMapping.size() > 0) { script.append("\n// SCRIPTS ATTACHED TO TYPE EVENTS\n\n").append("def FxType currentType\n") .append("def FxScriptInfo siType\n"); // traverse types and retrieve the scripts for (Long typeId : typeScriptMapping.keySet()) { final FxType t = CacheAdmin.getEnvironment().getType(typeId); final String typeName = t.getName(); // traverse events for the given type final Map<String, List<Long>> eventScripts = typeScriptMapping.get(typeId); for (String event : eventScripts.keySet()) { // retrieve the scripts for the given event final List<Long> scriptsForEvent = eventScripts.get(event); // traverse the script ids, retrieve the scripts and write out the code for (Long scriptId : scriptsForEvent) { final FxScriptInfo si = CacheAdmin.getEnvironment().getScript(scriptId); script.append(writeTypeScriptCode(event, si, typeName, scriptOverride)); } } } } // ASSIGNMENT SCRIPTS if (assignmentScriptMapping != null && assignmentScriptMapping.size() > 0) { script.append("\n// SCRIPTS ATTACHED TO ASSIGNMENT EVENTS\n\n") .append("def FxAssignment currentAssignment\n").append("def FxScriptInfo siAss\n"); // traverse assignments and retrieve the scripts for (Long assId : assignmentScriptMapping.keySet()) { final FxAssignment a = CacheAdmin.getEnvironment().getAssignment(assId); final String XPath = a.getXPath(); // traverse events for the given type final Map<String, List<Long>> eventScripts = assignmentScriptMapping.get(assId); for (String event : eventScripts.keySet()) { // retrieve the scripts fo einer the given event final List<Long> scriptsForEvent = eventScripts.get(event); // traverse the script ids, retrieve the scripts and write out the code for (Long scriptId : scriptsForEvent) { final FxScriptInfo si = CacheAdmin.getEnvironment().getScript(scriptId); script.append(writeAssignmentScriptCode(event, si, XPath, scriptOverride)); } } } } script.trimToSize(); return script.toString(); } /** * @param event the script event * @param si the FxScriptInfo * @param typeName the type's name * @param scriptOverride set to true if a given script should be overwritten * @return returns the script assignment as a Groovy script */ private static String writeTypeScriptCode(String event, FxScriptInfo si, String typeName, boolean scriptOverride) { final StringBuilder script = new StringBuilder(500); final FxScriptMapping sm = CacheAdmin.getEnvironment().getScriptMapping(si.getId()); boolean derivedUsage = false; for (FxScriptMappingEntry sme : sm.getMappedTypes()) { if (sme.getScriptId() == si.getId()) { derivedUsage = sme.isDerivedUsage(); break; } } // final String scriptCode = processScriptCode(si.getCode()); final String scriptCode; try { scriptCode = EJBLookup.getScriptingEngine().loadScriptCode(si.getId()); } catch (FxApplicationException e) { throw e.asRuntimeException(); } // load type in script, then append type name script.append("\n// ***** SCRIPT START ***** \n") .append("currentType = CacheAdmin.getEnvironment().getType(\"").append(typeName).append("\")\n\n") .append("scriptCode = \"\"\"").append(scriptCode).append("\"\"\"\n\n"); if (scriptOverride) { script.append(createScriptOverrideCode(si, event, true)); } else { script.append(createScriptEJBLookup(si, event, true)); } script.append("EJBLookup.getScriptingEngine().createTypeScriptMapping(FxScriptEvent.").append(event) .append(", siType.id, currentType.getId(), ").append(si.isActive()).append(", ") .append(derivedUsage).append(")\n// ***** SCRIPT END *****\n"); return script.toString(); } /** * @param event the event * @param si the FxScriptInfo * @param XPath the XPath of the affected assignment * @param scriptOverride set to true if a given script should be overwritten * @return the script assignment code as a Groovy script */ private static String writeAssignmentScriptCode(String event, FxScriptInfo si, String XPath, boolean scriptOverride) { final StringBuilder script = new StringBuilder(500); final FxScriptMapping sm = CacheAdmin.getEnvironment().getScriptMapping(si.getId()); boolean derivedUsage = false; for (FxScriptMappingEntry sme : sm.getMappedAssignments()) { if (sme.getScriptId() == si.getId()) { derivedUsage = sme.isDerivedUsage(); break; } } // final String scriptCode = processScriptCode(si.getCode()); final String scriptCode; try { scriptCode = EJBLookup.getScriptingEngine().loadScriptCode(si.getId()); } catch (FxApplicationException e) { throw e.asRuntimeException(); } // load assignment, then attach script to event and assignment id script.append("\n// ***** SCRIPT START ***** \n") .append("currentAssignment = CacheAdmin.getEnvironment().getAssignment(\"").append(XPath) .append("\")\n\n").append("scriptCode = \"\"\"").append(scriptCode).append("\"\"\"\n\n"); if (scriptOverride) { script.append(createScriptOverrideCode(si, event, false)); } else { script.append(createScriptEJBLookup(si, event, false)); } script.append("EJBLookup.getScriptingEngine().createAssignmentScriptMapping(FxScriptEvent.").append(event) .append(", siAss.id, currentAssignment.getId(), ").append(si.isActive()).append(", ") .append(derivedUsage).append(")\n// ***** SCRIPT END *****\n"); script.trimToSize(); return script.toString(); } /** * Create script code * * @param si FxScriptInfo * @param event event name * @param isType true if type assignment, false otherwise * @return returns the code as a String */ private static String createScriptEJBLookup(FxScriptInfo si, String event, boolean isType) { StringBuilder script = new StringBuilder(50); if (isType) script.append("siType = EJBLookup.getScriptingEngine().createScript(FxScriptEvent."); else script.append("siAss = EJBLookup.getScriptingEngine().createScript(FxScriptEvent."); script.append(event).append(", \"").append(si.getName()).append("\", \"").append(si.getDescription()) .append("\", scriptCode)\n"); script.trimToSize(); return script.toString(); } /** * Creates the script override code (incl. boolean switch) * * @param si FxScriptInfo * @param event event name * @param isType true if type assignment, false otherwise * @return returns the script code as a String */ private static String createScriptOverrideCode(FxScriptInfo si, String event, boolean isType) { StringBuilder script = new StringBuilder(100); script.append("try {\n").append("\tif(scriptOverride && CacheAdmin.getEnvironment().scriptExists(\"") .append(si.getName()).append("\")) {\n") .append("\t\tdef scriptId = CacheAdmin.getEnvironment().getScript(\"").append(si.getName()) .append("\").getId()\n") .append("\t\tEJBLookup.getScriptingEngine().updateScriptCode(scriptId, scriptCode)\n"); if (isType) script.append("\t\tsiType = CacheAdmin.getEnvironment().getScript(scriptId)\n"); else script.append("\t\tsiAss = CacheAdmin.getEnvironment().getScript(scriptId)\n"); script.append("\t} else {\n\t\t").append(createScriptEJBLookup(si, event, isType)).append("\t}\n") .append("} catch(FxApplicationException e) {\n // do nothing\n}\n"); script.trimToSize(); return script.toString(); } }