001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/metaobj/tags/sakai_2-4-1/metaobj-api/api/src/java/org/sakaiproject/metaobj/shared/model/ElementBean.java $
003: * $Id: ElementBean.java 20850 2007-02-01 00:05:58Z john.ellis@rsmart.com $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2004, 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.metaobj.shared.model;
021:
022: import java.io.ByteArrayOutputStream;
023: import java.io.IOException;
024: import java.util.ArrayList;
025: import java.util.Collection;
026: import java.util.HashMap;
027: import java.util.HashSet;
028: import java.util.Iterator;
029: import java.util.List;
030: import java.util.Map;
031: import java.util.Set;
032:
033: import org.apache.commons.logging.Log;
034: import org.apache.commons.logging.LogFactory;
035: import org.jdom.Attribute;
036: import org.jdom.Element;
037: import org.jdom.output.Format;
038: import org.jdom.output.XMLOutputter;
039: import org.sakaiproject.component.cover.ComponentManager;
040: import org.sakaiproject.metaobj.shared.mgt.FieldValueWrapperFactory;
041: import org.sakaiproject.metaobj.utils.TypedMap;
042: import org.sakaiproject.metaobj.utils.mvc.intf.FieldValueWrapper;
043: import org.sakaiproject.metaobj.utils.xml.NormalizationException;
044: import org.sakaiproject.metaobj.utils.xml.SchemaNode;
045:
046: /**
047: * Created by IntelliJ IDEA.
048: * User: John Ellis
049: * Date: Mar 10, 2004
050: * Time: 3:45:39 PM
051: * To change this template use File | Settings | File Templates.
052: */
053: public class ElementBean extends HashMap implements TypedMap {
054:
055: protected final Log logger = LogFactory.getLog(getClass());
056:
057: private Element baseElement;
058: private Map types = new HashMap();
059: private SchemaNode currentSchema;
060: private Map wrappedInstances = new HashMap();
061: private Map wrappedLists = new HashMap();
062: private boolean deferValidation = true;
063: private ElementListBean parent;
064:
065: public static final String FIELD_DATA_TAG = "FIELD_DATA";
066:
067: private static FieldValueWrapperFactory wrapperFactory = null;
068:
069: public ElementBean(String elementName, SchemaNode currentSchema) {
070: this .currentSchema = currentSchema;
071: setBaseElement(new Element(elementName));
072: }
073:
074: public ElementBean(String elementName, SchemaNode currentSchema,
075: boolean deferValidation) {
076: this .deferValidation = deferValidation;
077: this .currentSchema = currentSchema;
078: setBaseElement(new Element(elementName));
079: }
080:
081: public ElementBean() {
082: setBaseElement(new Element("empty"));
083: }
084:
085: public ElementBean(Element baseElement, SchemaNode currentSchema,
086: boolean deferValidation) {
087: this .deferValidation = deferValidation;
088: this .currentSchema = currentSchema;
089: setBaseElement(baseElement);
090: }
091:
092: public ElementBean(Element baseElement, SchemaNode currentSchema,
093: Map wrappedInstances) {
094: this .currentSchema = currentSchema;
095: this .wrappedInstances = wrappedInstances;
096: setBaseElement(baseElement);
097: }
098:
099: public Element currentElement() {
100: return baseElement;
101: }
102:
103: public SchemaNode getCurrentSchema() {
104: return currentSchema;
105: }
106:
107: public void setCurrentSchema(SchemaNode currentSchema) {
108: this .currentSchema = currentSchema;
109: }
110:
111: public Object put(Object key, Object value) {
112: logger.debug("put called with " + key + " and " + value
113: + " on " + baseElement.getName());
114:
115: SchemaNode elementSchema = currentSchema.getChild((String) key);
116:
117: if (getWrapperFactory().checkWrapper(
118: elementSchema.getObjectType())) {
119: return this .wrappedObjectPut(key, value, elementSchema);
120: }
121:
122: if (elementSchema.getMaxOccurs() == 1) {
123:
124: String normalizedValue;
125:
126: try {
127: normalizedValue = elementSchema
128: .getSchemaNormalizedValue(value);
129: } catch (NormalizationException exp) {
130: if (deferValidation) {
131: normalizedValue = value.toString();
132: } else {
133: throw exp;
134: }
135: }
136:
137: if (elementSchema.isAttribute()) {
138: Attribute oldAttribute = currentElement().getAttribute(
139: (String) key);
140: if (value != null && value.toString().length() > 0) {
141: logger.debug("not removing attribute" + key);
142: if (oldAttribute == null) {
143: currentElement().setAttribute(key.toString(),
144: normalizedValue);
145: } else {
146: oldAttribute.setValue(normalizedValue);
147: }
148: } else if (oldAttribute != null) {
149: logger.debug("removing attribute" + key);
150: currentElement().removeAttribute(key.toString());
151: }
152: } else {
153: Element oldElement = currentElement().getChild(
154: (String) key);
155:
156: if (value != null && value.toString().length() > 0) {
157: if (oldElement == null) {
158: Element newElement = new Element((String) key);
159: newElement.addContent(normalizedValue);
160: currentElement().addContent(newElement);
161: } else {
162: oldElement.setText(normalizedValue);
163: }
164: } else if (oldElement != null) {
165: currentElement().removeContent(oldElement);
166: }
167: }
168: } else {
169: // if you got here, must be a simple element
170: ElementListBean listBean = (ElementListBean) get(key);
171:
172: while (listBean.size() > 0) {
173: listBean.remove(0);
174: }
175:
176: if (value instanceof String[]) {
177:
178: String[] values = (String[]) value;
179:
180: for (int i = 0; i < values.length; i++) {
181: if (values[i].length() > 0) {
182: ElementBean bean = listBean.createBlank();
183: bean.getBaseElement().addContent(values[i]);
184: listBean.add(bean);
185: }
186: }
187: } else if (value instanceof String) {
188: if (value.toString().length() > 0) {
189: ElementBean bean = listBean.createBlank();
190: bean.getBaseElement().addContent((String) value);
191: listBean.add(bean);
192: }
193: }
194:
195: }
196:
197: return null;
198: }
199:
200: protected FieldValueWrapperFactory getWrapperFactory() {
201: if (wrapperFactory == null) {
202: wrapperFactory = (FieldValueWrapperFactory) ComponentManager
203: .getInstance().get("fieldValueWrapperFactory");
204: }
205: return wrapperFactory;
206: }
207:
208: public static void setWrapperFactory(
209: FieldValueWrapperFactory wrapperFactory) {
210: ElementBean.wrapperFactory = wrapperFactory;
211: }
212:
213: public Object remove(Object key) {
214: currentElement().removeChild((String) key);
215: types.remove(key);
216: return null;
217: }
218:
219: public Object get(Object key) {
220: logger.debug("get called with " + key);
221:
222: SchemaNode schema = currentSchema.getChild((String) key);
223:
224: if (schema == null) {
225: return null;
226: }
227:
228: if (schema.getMaxOccurs() > 1 || schema.getMaxOccurs() == -1) {
229: List childElements = new ArrayList();
230: List rawElements = baseElement.getChildren((String) key);
231: for (Iterator i = rawElements.iterator(); i.hasNext();) {
232: logger.debug("got child");
233: childElements.add(new ElementBean((Element) i.next(),
234: schema, deferValidation));
235: }
236:
237: if (getWrapperFactory()
238: .checkWrapper(schema.getObjectType())) {
239: return wrappedListGet(childElements, schema, key);
240: } else {
241: return new ElementListBean(baseElement, childElements,
242: schema, deferValidation);
243: }
244: }
245:
246: if (getWrapperFactory().checkWrapper(schema.getObjectType())) {
247: return this .wrappedObjectGet(key, schema);
248: }
249:
250: if (schema.isAttribute()) {
251: Attribute child = baseElement.getAttribute((String) key);
252:
253: if (child == null) {
254: return null;
255: } else {
256: try {
257: return schema.getActualNormalizedValue(child
258: .getValue());
259: } catch (NormalizationException exp) {
260: // This should not happen... values should already be validated...
261: // just return the text itself...
262: return child.getValue();
263: }
264: }
265: } else {
266: Element child = baseElement.getChild((String) key);
267:
268: if (child == null) {
269: if (schema.getObjectType().isAssignableFrom(
270: java.util.Map.class)) {
271: child = new Element(schema.getName());
272: baseElement.addContent(child);
273: } else {
274: return null;
275: }
276: }
277:
278: logger.debug("returning typed object");
279:
280: Class objectClass = schema.getObjectType();
281:
282: if (Map.class.isAssignableFrom(objectClass)) {
283: return new ElementBean(child, schema, deferValidation);
284: } else {
285: try {
286: return schema.getActualNormalizedValue(child
287: .getText());
288: } catch (NormalizationException exp) {
289: // This should not happen... values should already be validated...
290: // just return the text itself...
291: return child.getText();
292: }
293: }
294: }
295: }
296:
297: protected Object wrappedListGet(List childElements,
298: SchemaNode schema, Object key) {
299: if (wrappedLists.get(key) == null) {
300: wrappedLists.put(key, new ElementListBeanWrapper(
301: new ElementListBean(baseElement, childElements,
302: schema, deferValidation),
303: (FieldValueWrapper) wrappedObjectGet(key, schema)));
304: }
305:
306: return wrappedLists.get(key);
307: }
308:
309: protected Object wrappedObjectPut(Object key, Object value,
310: SchemaNode schema) {
311: FieldValueWrapper wrapper = (FieldValueWrapper) wrappedInstances
312: .get(key);
313:
314: if (wrapper == null) {
315: wrapper = getWrapperFactory().wrapInstance(value);
316: wrappedInstances.put(key, wrapper);
317: } else {
318: wrapper.setValue(value);
319: }
320:
321: Element childElement = getBaseElement().getChild(
322: schema.getName());
323:
324: if (childElement == null) {
325: childElement = new Element(schema.getName());
326: getBaseElement().addContent(childElement);
327: }
328:
329: childElement.setText(schema.getSchemaNormalizedValue(value));
330:
331: return null;
332: }
333:
334: protected Object wrappedObjectGet(Object key, SchemaNode schema) {
335: FieldValueWrapper wrapper = (FieldValueWrapper) wrappedInstances
336: .get(key);
337:
338: if (wrapper == null) {
339: wrapper = getWrapperFactory().wrapInstance(
340: schema.getObjectType());
341: wrappedInstances.put(key, wrapper);
342:
343: Element valueElement = getBaseElement().getChild(
344: schema.getName());
345:
346: if (valueElement != null
347: && valueElement.getContentSize() != 0) {
348: Object value = schema
349: .getActualNormalizedValue(valueElement
350: .getText());
351: wrapper.setValue(value);
352: }
353: }
354:
355: return wrapper;
356: }
357:
358: public Class getType(String key) {
359: SchemaNode schema = currentSchema.getChild(key);
360:
361: if (schema != null) {
362: if (schema.getMaxOccurs() > 1
363: || schema.getMaxOccurs() == -1) {
364: if (getWrapperFactory().checkWrapper(
365: schema.getObjectType())) {
366: return ElementListBeanWrapper.class;
367: } else {
368: return ElementListBean.class;
369: }
370: } else {
371: return schema.getObjectType();
372: }
373: }
374: return null;
375: }
376:
377: public String toString() {
378: return currentElement().getText();
379: }
380:
381: public void setBaseElement(Element element) {
382: this .baseElement = element;
383: }
384:
385: public Element getBaseElement() {
386: return baseElement;
387: }
388:
389: public boolean isDeferValidation() {
390: return deferValidation;
391: }
392:
393: public void setDeferValidation(boolean deferValidation) {
394: this .deferValidation = deferValidation;
395: }
396:
397: /**
398: * Generate a string containing XML tags and values representing the current contents of the element
399: *
400: * @return An XML String representation of the object
401: */
402: public String toXmlString() throws PersistenceException {
403: XMLOutputter outputter = new XMLOutputter();
404: ByteArrayOutputStream os = new ByteArrayOutputStream();
405:
406: try {
407: Format format = Format.getPrettyFormat();
408: outputter.setFormat(format);
409: outputter.output(getBaseElement(), os);
410: return new String(os.toByteArray());
411: //return os.toByteArray();
412: } catch (IOException e) {
413: throw new PersistenceException(e, "Unable to write object",
414: null, null);
415: }
416:
417: } // toXmlString
418:
419: class EntrySet implements Map.Entry {
420:
421: private Object key;
422: private Object value;
423:
424: //TODO what about equals and hashcode?
425:
426: public EntrySet(Object key, Object value) {
427: this .key = key;
428: this .value = value;
429: }
430:
431: /* (non-Javadoc)
432: * @see java.util.Map.Entry#getKey()
433: */
434: public Object getKey() {
435: return key;
436: }
437:
438: /* (non-Javadoc)
439: * @see java.util.Map.Entry#getValue()
440: */
441: public Object getValue() {
442: return value;
443: }
444:
445: /* (non-Javadoc)
446: * @see java.util.Map.Entry#setValue(java.lang.Object)
447: */
448: public Object setValue(Object value) {
449: // TODO Maybe throw an exception instead
450: this .value = value;
451: return this .value;
452: }
453:
454: }
455:
456: /* (non-Javadoc)
457: * @see java.util.Map#entrySet()
458: */
459: public Set entrySet() {
460: Set entries = new HashSet();
461: List children = currentSchema.getChildren();
462: for (Iterator iter = children.iterator(); iter.hasNext();) {
463: SchemaNode child = (SchemaNode) iter.next();
464: String key = child.getName();
465: Object value = get(key);
466: EntrySet entry = new EntrySet(key, value);
467: entries.add(entry);
468: }
469:
470: return entries;
471: }
472:
473: /* (non-Javadoc)
474: * @see java.util.Map#keySet()
475: */
476: public Set keySet() {
477: Set keys = new HashSet();
478: //List children = currentSchema.getChildren();
479: for (Iterator iter = entrySet().iterator(); iter.hasNext();) {
480: EntrySet child = (EntrySet) iter.next();
481: keys.add(child.getKey());
482: }
483: return keys;
484: }
485:
486: /* (non-Javadoc)
487: * @see java.util.Map#values()
488: */
489: public Collection values() {
490: Set values = new HashSet();
491: for (Iterator iter = entrySet().iterator(); iter.hasNext();) {
492: EntrySet child = (EntrySet) iter.next();
493: Object value = child.getValue();
494: values.add(value);
495: }
496: return values;
497: }
498:
499: public ElementListBean getParent() {
500: return parent;
501: }
502:
503: public void setParent(ElementListBean parent) {
504: this .parent = parent;
505: }
506:
507: public int getIndex() {
508: if (parent != null) {
509: return getParent().indexOf(this );
510: }
511: return 0;
512: }
513:
514: }
|