001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.uml.codegen.dataaccess;
042:
043: import java.util.ArrayList;
044: import java.util.HashMap;
045: import java.util.List;
046: import java.util.Set;
047:
048: import org.netbeans.modules.uml.codegen.dataaccess.xmlbeans.DomainObject;
049: import org.netbeans.modules.uml.codegen.dataaccess.xmlbeans.Family;
050: import org.netbeans.modules.uml.codegen.dataaccess.xmlbeans.Template;
051: import org.netbeans.modules.uml.codegen.dataaccess.xmlbeans.TemplateFamilies;
052: import org.netbeans.modules.uml.codegen.dataaccess.xmlbeans.TemplateFamiliesHandler;
053:
054: import org.netbeans.modules.uml.core.metamodel.core.foundation.INamedElement;
055: import org.netbeans.modules.uml.core.support.umlutils.ETList;
056: import org.netbeans.modules.uml.project.ProjectUtil;
057: import org.netbeans.modules.uml.project.UMLProject;
058: import org.netbeans.modules.uml.util.StringTokenizer2;
059:
060: /**
061: *
062: * @author Craig Conover, craig.conover@sun.com
063: */
064: public class DomainTemplatesRetriever {
065: public final static String TEMPLATES_BASE_FOLDER = "Templates/UML/Code Generation"; // NOI18N
066:
067: private static HashMap<String, List<DomainTemplate>> codeGenTemplates = null;
068:
069: public static void clear() {
070: codeGenTemplates = null;
071: }
072:
073: public static void load(UMLProject project) {
074: // get the enabled templates (domain objects)
075: // from project properties (from Project Customizer UI)
076: List<String> projectTemplates = project
077: .getUMLProjectProperties().getCodeGenTemplatesArray();
078:
079: // initialize to the size of the enabled templates
080: codeGenTemplates = new HashMap<String, List<DomainTemplate>>(
081: projectTemplates.size());
082:
083: // get all of the available templates (from UML Options UI)
084: TemplateFamiliesHandler dataHandler = TemplateFamiliesHandler
085: .getInstance(true);
086:
087: // TemplateFamilies templateFamilies = dataHandler.getTemplateFamilies();
088: TemplateFamilies templateFamilies = dataHandler
089: .getTemplateFamilies();
090:
091: if (templateFamilies == null)
092: throw new IllegalStateException(
093: "No Template Family Data Found"); // NOI18N
094:
095: // Load the codeGenTemplates HashMap with the enabled templates which
096: // are represented as CodeGenTemplate instances.
097: // This outer loop iterates over the enabled templates
098: // (from Project Customizer UI) which is a subset
099: // of the total number of available teamplate (from UML Options UI)
100: for (String projectTemplate : projectTemplates) {
101: // each enabled template is stored in the project properties as a
102: // pipe (|) delimited list of familyName:domainName pairs. The pipes
103: // are tokenized into a List for this loop to use
104: String[] tokens = StringTokenizer2.tokenize(
105: projectTemplate, ":");
106:
107: Family family = templateFamilies.getFamilyByName(tokens[0]);
108:
109: if (family == null)
110: continue;
111:
112: DomainObject domainObject = family
113: .getDomainByName(tokens[1]);
114:
115: if (domainObject == null)
116: continue;
117:
118: String elementType = domainObject.getModelElement();
119: String stereotype = domainObject.getStereotype();
120:
121: Template[] templateList = domainObject.getTemplate();
122: List<DomainTemplate> templates = new ArrayList<DomainTemplate>();
123:
124: for (Template template : templateList) {
125: String format = template.getFilenameFormat();
126: String ext = template.getFileExtension();
127: String path = template.getFolderPath();
128: String file = template.getTemplateFile();
129:
130: // Each domain has a list of template file(s) (usually just
131: // one) that are needed to generate code for the particular
132: // model element; i.e. - a "Class" element with a stereotype
133: // of "form" might have a template file for its source code,
134: // and another template file for its .form (metadata) file
135: // (think Matisse GUI editor).
136: // We need to create a CodeGenTemplate instance for each
137: // of these template files
138: // (see the CodeGenTemplate for more details)
139:
140: DomainTemplate cgt = new DomainTemplate("", format,
141: ext, path, file);
142:
143: templates.add(cgt);
144: }
145:
146: // the key to the hashmap will either be an element type or a
147: // combination of element type and stereotype
148: // i.e. - Class, or Class:foo
149:
150: String key = elementType;
151: if (stereotype != null && stereotype.length() > 0)
152: key += ":" + stereotype;
153:
154: // all templates, no matter which family they are in
155: // (Java, C++, etc.) will be added under this key
156: if (key != null && templates != null & templates.size() > 0) {
157: // if there are already templates added from another
158: // domain template, then add to the end of those
159: if (codeGenTemplates.containsKey(key)) {
160: List<DomainTemplate> curTemplates = codeGenTemplates
161: .get(key);
162: curTemplates.addAll(templates);
163: codeGenTemplates.put(key, curTemplates);
164: }
165:
166: else
167: codeGenTemplates.put(key, templates);
168: }
169: }
170: }
171:
172: public static List<DomainTemplate> retrieveTemplates(
173: INamedElement element) {
174: if (codeGenTemplates == null || codeGenTemplates.size() == 0)
175: load((UMLProject) ProjectUtil
176: .findReferencingProject(element));
177:
178: String eleType = element.getElementType();
179: ETList<String> stereotypes = element
180: .getAppliedStereotypesAsString();
181:
182: // Interface elements are also marked with the stereotype <<interface>>
183: // but we don't need the extra demarcation so remove it from the list
184: // of stereotypes it may have.
185: if (eleType.equals("Interface") && stereotypes != null
186: && stereotypes.size() > 0) {
187: stereotypes.remove("interface");
188: }
189:
190: // if the model element has no stereotypes, get enabled templates
191: // that do not have stereotypes
192: // TODO: but is this the right thing to do? See stereotype loop below
193: if (stereotypes == null || stereotypes.size() == 0) {
194: return insertElementName(element.getName(),
195: codeGenTemplates.get(eleType));
196: }
197:
198: List<DomainTemplate> validTemplates = new ArrayList<DomainTemplate>();
199:
200: // an element can have multiple stereotypes, so we need to get all
201: // templates that match all combinations of elementType:stereotype
202: // i.e. - if a model element is of type Class and has two stereotypes
203: // foo and bar, then we need to find any enbaled templates with
204: // a match for Class:foo and Class:bar
205: // TODO: if there is no match for Class:foo or Class:bar, do we return
206: // a match for Class with no stereotype? Currently, we are not
207: // doing that.
208: for (String stereotype : stereotypes) {
209: List<DomainTemplate> templates = codeGenTemplates
210: .get(eleType += ":" + stereotype);
211:
212: if (templates != null && templates.size() > 0)
213: validTemplates.addAll(templates);
214: }
215:
216: // the CodeGenTemplate instances don't have any element name and it
217: // would be convenient for the client of this class to have it preset
218: return insertElementName(element.getName(), validTemplates);
219: }
220:
221: private static List<DomainTemplate> insertElementName(
222: String elementName, List<DomainTemplate> templates) {
223: if (templates == null || templates.size() == 0)
224: return null;
225:
226: for (DomainTemplate cgt : templates)
227: cgt.setElementName(elementName);
228:
229: return templates;
230: }
231:
232: public static List<String> retrieveProjectEnabledModelElements() {
233: Set<String> keys = codeGenTemplates.keySet();
234: List<String> elementTypes = new ArrayList<String>(keys.size());
235:
236: for (String key : keys) {
237: int index = key.indexOf(':') + 1;
238: String eleType = "";
239:
240: if (index > 0)
241: eleType = key.substring(index);
242:
243: else
244: eleType = key;
245:
246: if (!elementTypes.contains(eleType))
247: elementTypes.add(eleType);
248: }
249:
250: return elementTypes;
251: }
252:
253: }
|