001: /*
002: The contents of this file are subject to the Common Public Attribution License
003: Version 1.0 (the "License"); you may not use this file except in compliance with
004: the License. You may obtain a copy of the License at
005: http://www.projity.com/license . The License is based on the Mozilla Public
006: License Version 1.1 but Sections 14 and 15 have been added to cover use of
007: software over a computer network and provide for limited attribution for the
008: Original Developer. In addition, Exhibit A has been modified to be consistent
009: with Exhibit B.
010:
011: Software distributed under the License is distributed on an "AS IS" basis,
012: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
013: specific language governing rights and limitations under the License. The
014: Original Code is OpenProj. The Original Developer is the Initial Developer and
015: is Projity, Inc. All portions of the code written by Projity are Copyright (c)
016: 2006, 2007. All Rights Reserved. Contributors Projity, Inc.
017:
018: Alternatively, the contents of this file may be used under the terms of the
019: Projity End-User License Agreeement (the Projity License), in which case the
020: provisions of the Projity License are applicable instead of those above. If you
021: wish to allow use of your version of this file only under the terms of the
022: Projity License and not to allow others to use your version of this file under
023: the CPAL, indicate your decision by deleting the provisions above and replace
024: them with the notice and other provisions required by the Projity License. If
025: you do not delete the provisions above, a recipient may use your version of this
026: file under either the CPAL or the Projity License.
027:
028: [NOTE: The text of this license may differ slightly from the text of the notices
029: in Exhibits A and B of the license at http://www.projity.com/license. You should
030: use the latest text at http://www.projity.com/license for your modifications.
031: You may not remove this license text from the source files.]
032:
033: Attribution Information: Attribution Copyright Notice: Copyright © 2006, 2007
034: Projity, Inc. Attribution Phrase (not exceeding 10 words): Powered by OpenProj,
035: an open source solution from Projity. Attribution URL: http://www.projity.com
036: Graphic Image as provided in the Covered Code as file: openproj_logo.png with
037: alternatives listed on http://www.projity.com/logo
038:
039: Display of Attribution Information is required in Larger Works which are defined
040: in the CPAL as a work which combines Covered Code or portions thereof with code
041: not governed by the terms of the CPAL. However, in addition to the other notice
042: obligations, all copies of the Covered Code in Executable and Source Code form
043: distributed must, as a form of attribution of the original author, include on
044: each user interface screen the "OpenProj" logo visible to all users. The
045: OpenProj logo should be located horizontally aligned with the menu bar and left
046: justified on the top left of the screen adjacent to the File menu. The logo
047: must be at least 100 x 25 pixels. When users click on the "OpenProj" logo it
048: must direct them back to http://www.projity.com.
049: */
050: package com.projity.configuration;
051:
052: import java.io.FileNotFoundException;
053: import java.io.FileOutputStream;
054: import java.io.IOException;
055: import java.util.Collection;
056: import java.util.Collections;
057: import java.util.HashMap;
058: import java.util.Iterator;
059: import java.util.LinkedList;
060: import java.util.List;
061:
062: import org.apache.commons.collections.Closure;
063: import org.apache.commons.collections.CollectionUtils;
064: import org.apache.commons.collections.MapIterator;
065: import org.apache.commons.collections.Predicate;
066: import org.apache.commons.collections.map.HashedMap;
067: import org.apache.commons.digester.Digester;
068:
069: import com.projity.contrib.util.Log;
070: import com.projity.contrib.util.LogFactory;
071: import com.projity.field.Field;
072: import com.projity.pm.assignment.Assignment;
073: import com.projity.pm.dependency.Dependency;
074: import com.projity.pm.resource.Resource;
075: import com.projity.pm.resource.ResourceImpl;
076: import com.projity.pm.task.NormalTask;
077: import com.projity.pm.task.Project;
078: import com.projity.strings.Messages;
079: import com.projity.util.ClassUtils;
080: import com.projity.util.Environment;
081:
082: /**
083: * Dictionary of all fields
084: */
085: public class FieldDictionary {
086: private static Log log = LogFactory.getLog(FieldDictionary.class);
087: private HashedMap map = new HashedMap();
088: private HashMap actionsMap = new HashMap();
089:
090: public void addField(Field field) {
091: if (field.isServer() && Environment.getStandAlone())
092: return;
093: field.setClass(clazz);
094: if (field.build() || true) {
095: if (field.isIndexed()) {
096: for (int i = 0; i < field.getIndexes(); i++) {
097: Field indexField = field.createIndexedField(i);
098: log.debug("adding indexfield " + clazz.getName()
099: + "." + indexField.getName() + " id "
100: + indexField.getId() + " field "
101: + indexField);
102: map.put(indexField.getId(), indexField);
103:
104: }
105: } else {
106: log.debug("adding field " + clazz.getName() + "."
107: + field.getName() + " " + field);
108: map.put(field.getId(), field);
109: if (field.getAction() != null)
110: actionsMap.put(field.getAction(), field);
111:
112: }
113: } else {
114: log.warn("Field not added" + field.getId());
115: }
116: }
117:
118: public Field getActionField(String action) {
119: return (Field) actionsMap.get(action);
120: }
121:
122: public static FieldDictionary getInstance() {
123: return Configuration.getInstance().getFieldDictionary();
124: }
125:
126: public Field getFieldFromId(String id) {
127: return (Field) map.get(id);
128: }
129:
130: private Class clazz;
131:
132: public void setClassName(String className) {
133: //System.out.println(" <include name=\""+className+"\"/>");
134: try {
135: clazz = ClassUtils.forName(className);
136: } catch (ClassNotFoundException e) {
137: // TODO Auto-generated catch block
138: e.printStackTrace();
139: }
140: }
141:
142: public void populateListWithFieldsOfType(List list, Class clazz) {
143: populateListWithFieldsOfType(list, new Class[] { clazz });
144: }
145:
146: /** Fill a collection with all fields that are applicable to one or more types
147: * specified by clazz. The collection is sorted alpha-numerically by field name.
148: * Lists by type should probably just be cached in static variables.
149: * @param collection - collection to fill
150: * @param clazz - array of class types
151: */
152: public void populateListWithFieldsOfType(List list, Class[] clazz) {
153: MapIterator i = map.mapIterator();
154: while (i.hasNext()) {
155: Object key = i.next();
156: Field field = (Field) i.getValue();
157: if (field.isApplicable(clazz))
158: list.add(field);
159: }
160: Collections.sort(list);
161: }
162:
163: Collection getAllFields() {
164: return map.values();
165: }
166:
167: private LinkedList taskFields = new LinkedList();
168: private LinkedList resourceFields = new LinkedList();
169: private LinkedList assignmentFields = new LinkedList();
170: private LinkedList dependencyFields = new LinkedList();
171: private LinkedList projectFields = new LinkedList();
172: private LinkedList taskAndAssignmentFields = new LinkedList();
173: private LinkedList resourceAndAssignmentFields = new LinkedList();
174:
175: void setDonePopulating() {
176: // in case we use a FastHashMap do this: map.setFast(true);
177: taskFields = new LinkedList();
178: resourceFields = new LinkedList();
179: assignmentFields = new LinkedList();
180: dependencyFields = new LinkedList();
181: projectFields = new LinkedList();
182: taskAndAssignmentFields = new LinkedList();
183: resourceAndAssignmentFields = new LinkedList();
184:
185: populateListWithFieldsOfType(taskFields, NormalTask.class);
186: populateListWithFieldsOfType(resourceFields, ResourceImpl.class);
187: populateListWithFieldsOfType(assignmentFields, Assignment.class);
188: populateListWithFieldsOfType(dependencyFields, Dependency.class);
189: populateListWithFieldsOfType(projectFields, Project.class);
190: populateListWithFieldsOfType(taskAndAssignmentFields,
191: new Class[] { NormalTask.class, Assignment.class });
192: populateListWithFieldsOfType(resourceAndAssignmentFields,
193: new Class[] { Resource.class, Assignment.class });
194: }
195:
196: /**
197: * @return Returns the assignmentFields.
198: */
199: public LinkedList getAssignmentFields() {
200: return assignmentFields;
201: }
202:
203: /**
204: * @return Returns the dependencyFields.
205: */
206: public LinkedList getDependencyFields() {
207: return dependencyFields;
208: }
209:
210: /**
211: * @return Returns the projectFields.
212: */
213: public LinkedList getProjectFields() {
214: return projectFields;
215: }
216:
217: /**
218: * @return Returns the resourceFields.
219: */
220: public LinkedList getResourceFields() {
221: return resourceFields;
222: }
223:
224: /**
225: * @return Returns the taskAndAssignmentFields.
226: */
227: public LinkedList getTaskAndAssignmentFields() {
228: return taskAndAssignmentFields;
229: }
230:
231: /**
232: * @return Returns the taskFields.
233: */
234: public LinkedList getTaskFields() {
235: return taskFields;
236: }
237:
238: /**
239: * @return Returns the resourceAndAssignmentFields.
240: */
241: public LinkedList getResourceAndAssignmentFields() {
242: return resourceAndAssignmentFields;
243: }
244:
245: /**
246: * Extract fields that have extra status, and also optionally that have validOnOjbectCreate status
247: */
248: public static LinkedList extractExtraFields(Collection from,
249: final boolean mustBeValidOnObjectCreate) {
250: LinkedList result = new LinkedList();
251: CollectionUtils.select(from, new Predicate() {
252: public boolean evaluate(Object arg0) {
253: Field f = (Field) arg0;
254: return f.isExtra()
255: && (!mustBeValidOnObjectCreate || f
256: .isValidOnObjectCreate());
257: }
258: }, result);
259: return result;
260: }
261:
262: public static void addDigesterEvents(Digester digester) {
263: // digester.addObjectCreate("*/fieldDictionary", "com.projity.configuration.FieldDictionary");
264: digester.addFactoryCreate("*/fieldDictionary",
265: "com.projity.configuration.FieldDictionaryFactory");
266: digester.addSetNext("*/fieldDictionary", "setFieldDictionary",
267: "com.projity.configuration.FieldDictionary"); //TODO can we do this more easily
268: digester.addSetProperties("*/fieldDictionary/class", "name",
269: "className"); // object is field dictionary
270: digester.addObjectCreate("*/fieldDictionary/class/field",
271: "com.projity.field.Field");
272: digester.addSetProperties("*/fieldDictionary/class/field");
273: digester.addSetNext("*/fieldDictionary/class/field",
274: "addField", "com.projity.field.Field");
275:
276: digester.addObjectCreate("*/field/select",
277: "com.projity.field.StaticSelect"); // create a select
278: digester.addSetProperties("*/field/select"); // set name of select
279: digester.addSetNext("*/field/select", "setSelect",
280: "com.projity.field.StaticSelect"); // attach to field
281:
282: digester.addObjectCreate("*/field/choice",
283: "com.projity.field.DynamicSelect"); // create a cohice
284: digester.addSetProperties("*/field/choice"); // set name of choice, finder and list methods
285: digester.addSetNext("*/field/choice", "setSelect",
286: "com.projity.field.DynamicSelect"); // attach to field
287:
288: digester.addObjectCreate("*/field/select/option",
289: "com.projity.field.SelectOption"); // create an option when seeing one
290: digester.addSetProperties("*/field/select/option"); // get key and value properties
291: digester.addSetNext("*/field/select/option", "addOption",
292: "com.projity.field.SelectOption"); // add option to select
293:
294: digester.addObjectCreate("*/field/range",
295: "com.projity.field.Range"); // create an option when seeing one
296: digester.addSetProperties("*/field/range"); // get key and value properties
297: digester.addSetNext("*/field/range", "setRange",
298: "com.projity.field.Range"); // add option to select
299:
300: //non intrusive method to reduce role options, otherwise Select should be modified to depend on a specific object
301: digester.addObjectCreate("*/field/filter",
302: "com.projity.field.OptionsFilter");
303: digester.addSetProperties("*/field/filter");
304: digester.addSetNext("*/field/filter", "setFilter",
305: "com.projity.field.OptionsFilter");
306:
307: String fieldAccessibleClass = Messages
308: .getMetaString("FieldAccessible");
309: digester.addObjectCreate("*/field/permission",
310: fieldAccessibleClass);
311: digester.addSetProperties("*/field/permission");
312: digester.addSetNext("*/field/permission", "setAccessControl",
313: "com.projity.field.FieldAccessible");
314:
315: }
316:
317: private static void tabbedStringToHtmlRow(StringBuffer result,
318: String colString, boolean header) {
319: result.append("<tr>");
320: String[] cols = colString.split("\t");
321: for (String col : cols)
322: result.append(header ? "<th>" : "<td>").append(col).append(
323: header ? "</th>" : "</td>");
324: result.append("</tr>");
325: }
326:
327: private static void fieldsToHtmlTable(final StringBuffer result,
328: String title, Collection fields) {
329: result.append("<p><b>").append(title).append("</b><br />");
330: result.append("<table border='1'>");
331: tabbedStringToHtmlRow(result, Field.getMetadataStringHeader(),
332: true);
333: CollectionUtils.forAllDo(FieldDictionary.getInstance()
334: .getProjectFields(), new Closure() {
335: public void execute(Object arg0) {
336: tabbedStringToHtmlRow(result, ((Field) arg0)
337: .getMetadataString(), false);
338: }
339: });
340: result.append("</table>");
341: result.append("</p>");
342: }
343:
344: public static void generateFieldDoc(String fileName) {
345: StringBuffer result = new StringBuffer();
346: result.append("<html><body>");
347: fieldsToHtmlTable(result, "Project Fields", FieldDictionary
348: .getInstance().getProjectFields());
349: fieldsToHtmlTable(result, "Resource Fields", FieldDictionary
350: .getInstance().getProjectFields());
351: fieldsToHtmlTable(result, "Task Fields", FieldDictionary
352: .getInstance().getProjectFields());
353: fieldsToHtmlTable(result, "Assignment Fields", FieldDictionary
354: .getInstance().getProjectFields());
355: fieldsToHtmlTable(result, "Dependency Fields", FieldDictionary
356: .getInstance().getProjectFields());
357: result.append("</body></html>");
358:
359: try {
360: new FileOutputStream(fileName).write(result.toString()
361: .getBytes());
362: } catch (FileNotFoundException e) {
363: // TODO Auto-generated catch block
364: e.printStackTrace();
365: } catch (IOException e) {
366: // TODO Auto-generated catch block
367: e.printStackTrace();
368: }
369: }
370:
371: public static void main(String args[]) {
372: generateFieldDoc("d:/pod/fields.html");
373: }
374:
375: public static HashMap getAliasMap() {
376: HashMap aliasMap = new HashMap();
377: MapIterator i = getInstance().map.mapIterator();
378: while (i.hasNext()) {
379: Object key = i.next();
380: Field field = (Field) i.getValue();
381: if (field.getAlias() != null)
382: aliasMap.put(field.getId(), field.getAlias());
383: }
384: return aliasMap;
385: }
386:
387: public static void setAliasMap(HashMap aliasMap) {
388: Iterator i = aliasMap.keySet().iterator();
389: while (i.hasNext()) {
390: String fieldId = (String) i.next();
391: Field f = Configuration.getFieldFromId(fieldId);
392: f.setAlias((String) aliasMap.get(fieldId));
393: }
394: }
395:
396: }
|