001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package org.terracotta.dso.editors.xmlbeans;
005:
006: import org.apache.xmlbeans.SchemaProperty;
007: import org.apache.xmlbeans.SchemaStringEnumEntry;
008: import org.apache.xmlbeans.SchemaType;
009: import org.apache.xmlbeans.StringEnumAbstractBase;
010: import org.apache.xmlbeans.XmlAnySimpleType;
011: import org.apache.xmlbeans.XmlInteger;
012: import org.apache.xmlbeans.XmlObject;
013: import org.apache.xmlbeans.XmlToken;
014:
015: import java.lang.reflect.Method;
016: import java.text.NumberFormat;
017: import java.util.ArrayList;
018: import java.util.StringTokenizer;
019:
020: import javax.xml.namespace.QName;
021:
022: // TODO: assign all static values to instance variable instead of constant
023: // reflection-based lookup. Examples include: isRequired, hasDefault, defaultText.
024:
025: public class XmlObjectHolderHelper {
026: private XmlObject m_parent;
027: private Class m_parentType;
028: private SchemaType m_parentSchemaType;
029: private String m_elementName;
030: private String m_fieldName;
031: private SchemaProperty m_schemaProperty;
032: private SchemaType m_propertySchemaType;
033: private String m_defaultStringValue;
034:
035: private transient ArrayList<XmlObjectStructureListener> m_listenerList;
036: private transient XmlObjectStructureChangeEvent m_changeEvent;
037:
038: private static final Class[] NO_PARAMS = new Class[0];
039: private static final Object[] NO_ARGS = new Object[0];
040:
041: public XmlObject getParent() {
042: return m_parent;
043: }
044:
045: public Class getParentType() {
046: return m_parentType;
047: }
048:
049: public String getElementName() {
050: return m_elementName;
051: }
052:
053: public String getFieldName() {
054: return m_fieldName;
055: }
056:
057: public void init(Class parentType, String elementName) {
058: m_parentType = parentType;
059: m_elementName = elementName;
060: m_fieldName = convertElementName(elementName);
061:
062: // this is here because some elementNames ("class") don't cleanly map to
063: // their fieldName ("Class1")
064: if (Character.isDigit(elementName
065: .charAt(elementName.length() - 1))) {
066: m_elementName = elementName.substring(0, elementName
067: .length() - 1);
068: }
069:
070: m_parentSchemaType = null;
071: m_schemaProperty = null;
072: m_propertySchemaType = null;
073: m_defaultStringValue = null;
074: }
075:
076: public void setup(XmlObject parent) {
077: m_parent = parent;
078: if (m_changeEvent != null) {
079: m_changeEvent.setXmlObject(parent);
080: }
081: }
082:
083: public void tearDown() {
084: m_parent = null;
085: if (m_changeEvent != null) {
086: m_changeEvent.setXmlObject(null);
087: }
088: }
089:
090: private static String convertElementName(String s) {
091: StringBuffer sb = new StringBuffer();
092: StringTokenizer st = new StringTokenizer(s, "-");
093: String tok;
094:
095: while (st.hasMoreTokens()) {
096: tok = st.nextToken();
097: sb.append(Character.toUpperCase(tok.charAt(0)));
098: sb.append(tok.substring(1));
099: }
100:
101: return sb.toString();
102: }
103:
104: public XmlObject getXmlObject() {
105: if (m_parent != null) {
106: try {
107: return (XmlObject) invokePrefixedParentNoParams("xget");
108: } catch (Exception e) {
109: e.printStackTrace();
110: }
111: }
112:
113: return null;
114: }
115:
116: public XmlObject ensureXmlObject() {
117: XmlObject xmlObject = null;
118:
119: if (m_parent != null && (xmlObject = getXmlObject()) == null) {
120: try {
121: Class[] params = new Class[] { getPropertySchemaType()
122: .getJavaClass() };
123: Object[] args = new Object[] { getSchemaProperty()
124: .getDefaultValue() };
125: String methodName = "xset" + m_fieldName;
126: Method method = m_parentType.getMethod(methodName,
127: params);
128:
129: method.invoke(m_parent, args);
130:
131: xmlObject = getXmlObject();
132: } catch (Exception e) {
133: e.printStackTrace();
134: }
135: }
136:
137: return xmlObject;
138: }
139:
140: private SchemaType getParentSchemaType() {
141: if (m_parentSchemaType == null) {
142: try {
143: m_parentSchemaType = (SchemaType) m_parentType
144: .getField("type").get(null);
145: } catch (Exception e) {
146: e.printStackTrace();
147: }
148: }
149:
150: return m_parentSchemaType;
151: }
152:
153: private SchemaProperty getSchemaProperty() {
154: if (m_schemaProperty == null) {
155: QName qname = QName.valueOf(m_elementName);
156: SchemaType type = getParentSchemaType();
157:
158: if ((m_schemaProperty = type.getElementProperty(qname)) == null) {
159: m_schemaProperty = type.getAttributeProperty(qname);
160: }
161: }
162:
163: return m_schemaProperty;
164: }
165:
166: private SchemaType getPropertySchemaType() {
167: if (m_propertySchemaType == null) {
168: m_propertySchemaType = getSchemaProperty().getType();
169: }
170: return m_propertySchemaType;
171: }
172:
173: // TODO: make ivar
174: public boolean hasStringEnumValues() {
175: return getPropertySchemaType().hasStringEnumValues();
176: }
177:
178: // TODO: make lazy ivar
179: public StringEnumAbstractBase[] getEnumValues() {
180: SchemaStringEnumEntry[] enumEntries = getPropertySchemaType()
181: .getStringEnumEntries();
182: int size = enumEntries.length;
183: StringEnumAbstractBase[] entries = new StringEnumAbstractBase[size];
184:
185: for (int i = 0; i < size; i++) {
186: entries[i] = enumForInt(enumEntries[i].getIntValue());
187: }
188:
189: return entries;
190: }
191:
192: // TODO: make lazy ivar
193: public StringEnumAbstractBase defaultEnumValue() {
194: return enumForString(defaultStringValue());
195: }
196:
197: // TODO: make ivar
198: public boolean isRequired() {
199: return getSchemaProperty().getMinOccurs().intValue() > 0;
200: }
201:
202: // TODO: make ivar
203: public boolean hasDefault() {
204: return getSchemaProperty().hasDefault() > 0;
205: }
206:
207: public boolean isSet() {
208: if (m_parent == null) {
209: return false;
210: }
211:
212: if (isRequired()) {
213: return true;
214: }
215:
216: try {
217: return ((Boolean) invokePrefixedParentNoParams("isSet"))
218: .booleanValue();
219: } catch (Exception e) {
220: e.printStackTrace();
221: return false;
222: }
223: }
224:
225: public StringEnumAbstractBase getEnumValue() {
226: try {
227: return enumForString(((XmlToken) getXmlObject())
228: .getStringValue());
229: } catch (Exception e) {
230: return defaultEnumValue();
231: }
232: }
233:
234: public StringEnumAbstractBase enumForInt(int i) {
235: return getPropertySchemaType().enumForInt(i);
236: }
237:
238: public StringEnumAbstractBase enumForString(String s) {
239: return getPropertySchemaType().enumForString(s);
240: }
241:
242: private XmlAnySimpleType getPropertyFacet(int facet) {
243: return getPropertySchemaType().getFacet(facet);
244: }
245:
246: public Integer minInclusive() {
247: XmlInteger min = (XmlInteger) getPropertyFacet(SchemaType.FACET_MIN_INCLUSIVE);
248: return Integer.valueOf(min.getBigIntegerValue().intValue());
249: }
250:
251: public Integer maxInclusive() {
252: XmlInteger min = (XmlInteger) getPropertyFacet(SchemaType.FACET_MAX_INCLUSIVE);
253: return Integer.valueOf(min.getBigIntegerValue().intValue());
254: }
255:
256: // TODO: make lazy ivar
257: public int defaultInteger() {
258: return parseInt(defaultStringValue());
259: }
260:
261: // TODO: make lazy ivar
262: public Integer defaultIntegerValue() {
263: return Integer.valueOf(defaultInteger());
264: }
265:
266: public int getInteger() {
267: return parseInt(getStringValue(), defaultInteger());
268: }
269:
270: public Integer getIntegerValue() {
271: return Integer.valueOf(getInteger());
272: }
273:
274: // TODO: make lazy ivar
275: public boolean defaultBoolean() {
276: return defaultBooleanValue().booleanValue();
277: }
278:
279: // TODO: make lazy ivar
280: public Boolean defaultBooleanValue() {
281: return Boolean.valueOf(defaultStringValue());
282: }
283:
284: public boolean getBoolean() {
285: return getBooleanValue().booleanValue();
286: }
287:
288: public Boolean getBooleanValue() {
289: return Boolean.valueOf(getStringValue());
290: }
291:
292: public String defaultStringValue() {
293: if (m_defaultStringValue == null) {
294: m_defaultStringValue = getSchemaProperty().getDefaultText();
295: }
296: return m_defaultStringValue;
297: }
298:
299: public String getStringValue() {
300: XmlAnySimpleType o = (XmlAnySimpleType) getXmlObject();
301: return o != null ? o.getStringValue() : null;
302: }
303:
304: public void set(String text) {
305: if (m_parent == null) {
306: return;
307: }
308:
309: try {
310: XmlObject xmlObject = ensureXmlObject();
311: Class[] params = new Class[] { String.class };
312: Object[] args = new Object[] { text };
313: String methodName = "setStringValue";
314: Class objClass = xmlObject.getClass();
315: Method method = objClass.getMethod(methodName, params);
316:
317: method.invoke(xmlObject, args);
318: fireXmlObjectStructureChanged();
319: } catch (Exception e) {
320: e.printStackTrace();
321: }
322: }
323:
324: public void unset() {
325: if (m_parent == null || isRequired() || !isSet()) {
326: return;
327: }
328:
329: try {
330: invokePrefixedParentNoParams("unset");
331: fireXmlObjectStructureChanged();
332: } catch (Exception e) {
333: e.printStackTrace();
334: }
335: }
336:
337: private Object invokePrefixedParentNoParams(String prefix)
338: throws Exception {
339: Method method = m_parentType.getMethod(prefix + m_fieldName,
340: NO_PARAMS);
341: return (method != null) ? method.invoke(m_parent, NO_ARGS)
342: : null;
343: }
344:
345: public synchronized void addXmlObjectStructureListener(
346: XmlObjectStructureListener listener) {
347: if (listener != null) {
348: if (m_listenerList == null) {
349: m_listenerList = new ArrayList<XmlObjectStructureListener>();
350: }
351: m_listenerList.add(listener);
352: }
353: }
354:
355: public synchronized void removeXmlObjectStructureListener(
356: XmlObjectStructureListener listener) {
357: if (listener != null) {
358: if (m_listenerList != null) {
359: m_listenerList.remove(listener);
360: }
361: }
362: }
363:
364: private XmlObjectStructureChangeEvent getChangeEvent() {
365: if (m_changeEvent == null) {
366: m_changeEvent = new XmlObjectStructureChangeEvent();
367: if (m_parent != null) {
368: m_changeEvent.setXmlObject(m_parent);
369: }
370: }
371:
372: return m_changeEvent;
373: }
374:
375: private XmlObjectStructureListener[] getListenerArray() {
376: return m_listenerList
377: .toArray(new XmlObjectStructureListener[0]);
378: }
379:
380: protected synchronized void fireXmlObjectStructureChanged() {
381: if (m_listenerList != null) {
382: XmlObjectStructureListener[] listeners = getListenerArray();
383: XmlObjectStructureChangeEvent event = getChangeEvent();
384:
385: for (int i = 0; i < listeners.length; i++) {
386: listeners[i].structureChanged(event);
387: }
388: }
389: }
390:
391: protected static int parseInt(String s) {
392: return parseInt(s, 42);
393: }
394:
395: protected static int parseInt(String s, int defaultValue) {
396: try {
397: return NumberFormat.getIntegerInstance().parse(s)
398: .intValue();
399: } catch (Exception e) {
400: return defaultValue;
401: }
402: }
403: }
|