001: package nl.hippo.cms.wizard;
002:
003: import java.util.EmptyStackException;
004: import java.util.HashMap;
005: import java.util.Map;
006: import java.util.Stack;
007:
008: import nl.hippo.cms.wizard.aspects.Aspects;
009: import nl.hippo.cms.wizard.aspects.ComponentAspect;
010: import nl.hippo.cms.wizard.components.Configurable;
011: import nl.hippo.cms.wizard.components.Configuration;
012: import nl.hippo.cms.wizard.components.Component;
013: import nl.hippo.cms.wizard.components.ComponentContainer;
014: import nl.hippo.cms.wizard.engines.Engine;
015: import nl.hippo.cms.wizard.widgets.Widget;
016:
017: import org.xml.sax.Attributes;
018: import org.xml.sax.ContentHandler;
019: import org.xml.sax.Locator;
020: import org.xml.sax.SAXException;
021:
022: /**
023: * ContentHandler for a wizard-configuration file. Instantiates a new Wizard component and wires it's subcomponents.
024: * Uses a ComponentBuilder to construct new components.
025: *
026: * @author a.bogaart@hippo.nl
027: *
028: */
029: public class WizardConfigurationContentHandler implements
030: ContentHandler {
031:
032: private ComponentBuilder builder;
033:
034: //Wizard and engine components
035: private Wizard wizard;
036: private Stack components;
037: private Stack containerComponents;
038: private Aspects aspects;
039:
040: public WizardConfigurationContentHandler() {
041: builder = new ComponentBuilder();
042: components = new Stack();
043: containerComponents = new Stack();
044: aspects = new Aspects();
045: }
046:
047: public Wizard getWizard() {
048: return wizard;
049: }
050:
051: public Aspects getAspects() {
052: return aspects;
053: }
054:
055: public void startElement(String namespaceURI, String localName,
056: String qName, Attributes atts) throws SAXException {
057:
058: if (Constants.INSTANCE_NAMESPACES.contains(namespaceURI)) {
059:
060: if (namespaceURI.equals(Constants.NS_URI_ASPECT)) {
061: if (components.size() == 0)
062: throw new SAXException("Aspect[" + localName
063: + "] must be nested inside a Component");
064: aspects.addAspect((Component) components.peek(),
065: (ComponentAspect) builder.create(namespaceURI,
066: localName, atts));
067: } else {
068: try {
069: if (namespaceURI.equals(Constants.NS_URI_WIZARD)) {
070: if ((components.size() + containerComponents
071: .size()) > 0)
072: throw new SAXException(
073: "Wizard element should be top level component");
074:
075: Component wizard = (Component) builder.create(
076: namespaceURI, localName, atts);
077: containerComponents.push(wizard);
078: components.push(wizard);
079: this .wizard = (Wizard) wizard;
080:
081: } else if (namespaceURI
082: .equals(Constants.NS_URI_ENGINE)) {
083: if (!(components.peek() instanceof Wizard))
084: throw new SAXException(
085: "Element engine:"
086: + localName
087: + " should be wrapped by a wizard element");
088:
089: Component engine = (Component) builder.create(
090: namespaceURI, localName, atts);
091: ((ComponentContainer) containerComponents
092: .peek()).addComponent(engine);
093: containerComponents.push(engine);
094: components.push(engine);
095:
096: } else if (namespaceURI
097: .equals(Constants.NS_URI_RESOURCE)) {
098: if (!(components.peek() instanceof Engine))
099: throw new SAXException(
100: "Element resource:"
101: + localName
102: + " should be wrapped by an engine element");
103:
104: Component resource = (Component) builder
105: .create(namespaceURI, localName, atts);
106: ((ComponentContainer) containerComponents
107: .peek()).addComponent(resource);
108: containerComponents.push(resource);
109: components.push(resource);
110:
111: } else if (namespaceURI
112: .equals(Constants.NS_URI_WIDGET)) {
113: if (!(components.peek() instanceof ComponentContainer))
114: throw new SAXException(
115: "Element widget:"
116: + localName
117: + " should be wrapped by a ComponentContainer element");
118:
119: Widget widget = (Widget) builder.create(
120: namespaceURI, localName, atts);
121: ((ComponentContainer) containerComponents
122: .peek()).addComponent(widget);
123: if (widget instanceof ComponentContainer) {
124: containerComponents
125: .push((ComponentContainer) widget);
126: }
127: components.push(widget);
128:
129: }
130: } catch (EmptyStackException e) {
131: throw new SAXException(
132: "No components in Component stack while trying to add "
133: + localName + "(" + namespaceURI
134: + ") to the model");
135: }
136: }
137: }
138: }
139:
140: public void endElement(String namespaceURI, String localName,
141: String qName) throws SAXException {
142: if (Constants.INSTANCE_NAMESPACES.contains(namespaceURI)
143: && !namespaceURI.equals(Constants.NS_URI_ASPECT)) {
144: if (components.peek() instanceof ComponentContainer) {
145: containerComponents.pop();
146: }
147:
148: //initialize components, provides a way for components to check their configuration against the 'live' model
149: Component comp = (Component) components.pop();
150: comp.initialize();
151:
152: }
153: }
154:
155: public void characters(char[] ch, int start, int length)
156: throws SAXException {
157:
158: }
159:
160: public void startDocument() throws SAXException {
161: }
162:
163: public void endDocument() throws SAXException {
164: components.clear();
165: containerComponents.clear();
166: }
167:
168: public void ignorableWhitespace(char[] ch, int start, int length)
169: throws SAXException {
170: }
171:
172: public void endPrefixMapping(String prefix) throws SAXException {
173: }
174:
175: public void skippedEntity(String name) throws SAXException {
176: }
177:
178: public void setDocumentLocator(Locator locator) {
179: }
180:
181: public void processingInstruction(String target, String data)
182: throws SAXException {
183: }
184:
185: public void startPrefixMapping(String prefix, String uri)
186: throws SAXException {
187: }
188:
189: /**
190: * Helper class for instantiating wizard components.
191: *
192: */
193: class ComponentBuilder {
194: private static final String PACKAGE_URI_WIZARD = "nl.hippo.cms.wizard.";
195: private static final String PACKAGE_URI_RESOURCE = "nl.hippo.cms.wizard.resources.";
196: private static final String PACKAGE_URI_ENGINE = "nl.hippo.cms.wizard.engines.";
197: private static final String PACKAGE_URI_WIDGET = "nl.hippo.cms.wizard.widgets.";
198: private static final String PACKAGE_URI_ASPECT = "nl.hippo.cms.wizard.aspects.";
199:
200: private static final String WIZARD_INTERFACE = "Wizard";
201: private static final String RESOURCE_INTERFACE = "Resource";
202: private static final String ENGINE_INTERFACE = "Engine";
203: private static final String WIDGET_INTERFACE = "Widget";
204: private static final String ASPECT_INTERFACE = "Aspect";
205:
206: private Map NS_URI_TO_PACKAGE = new HashMap();
207: private Map NS_URI_TO_INTERFACE = new HashMap();
208:
209: private int componentCount;
210:
211: public ComponentBuilder() {
212: componentCount = 0;
213:
214: NS_URI_TO_PACKAGE.put(Constants.NS_URI_WIZARD,
215: PACKAGE_URI_WIZARD);
216: NS_URI_TO_PACKAGE.put(Constants.NS_URI_ENGINE,
217: PACKAGE_URI_ENGINE);
218: NS_URI_TO_PACKAGE.put(Constants.NS_URI_RESOURCE,
219: PACKAGE_URI_RESOURCE);
220: NS_URI_TO_PACKAGE.put(Constants.NS_URI_WIDGET,
221: PACKAGE_URI_WIDGET);
222: NS_URI_TO_PACKAGE.put(Constants.NS_URI_ASPECT,
223: PACKAGE_URI_ASPECT);
224:
225: NS_URI_TO_INTERFACE.put(Constants.NS_URI_WIZARD,
226: WIZARD_INTERFACE);
227: NS_URI_TO_INTERFACE.put(Constants.NS_URI_ENGINE,
228: ENGINE_INTERFACE);
229: NS_URI_TO_INTERFACE.put(Constants.NS_URI_RESOURCE,
230: RESOURCE_INTERFACE);
231: NS_URI_TO_INTERFACE.put(Constants.NS_URI_WIDGET,
232: WIDGET_INTERFACE);
233: NS_URI_TO_INTERFACE.put(Constants.NS_URI_ASPECT,
234: ASPECT_INTERFACE);
235: }
236:
237: /**
238: * Create a new Wizard Component. First lookup package and interface values by namespace.
239: * Make sure class name starts with a CAP. Then create new instance and see if it's configurable.
240: * If so, make sure an id value exists and concatenate it with the parent's id value, then call configure().
241: * Check if new instance is an ComponentAspect and, if so, hook it up with the Component at the peek of the
242: * components stack.
243: */
244: public Object create(String namespace, String name,
245: Attributes atts) throws SAXException {
246: String instanceName = name.substring(0, 1).toUpperCase()
247: + name.substring(1);
248: String packageURI = (String) NS_URI_TO_PACKAGE
249: .get(namespace);
250: String interfaceName = (String) NS_URI_TO_INTERFACE
251: .get(namespace);
252: String className = packageURI + instanceName
253: + interfaceName;
254:
255: Object newObject;
256: try {
257: Class c = Class.forName(className);
258:
259: newObject = c.newInstance();
260: } catch (InstantiationException e) {
261: throw new SAXException(
262: "Error creating component className "
263: + className, e);
264: } catch (IllegalAccessException e) {
265: throw new SAXException(
266: "Error creating component className "
267: + className, e);
268: } catch (ClassNotFoundException e) {
269: throw new SAXException("Class " + className
270: + " not found", e);
271: }
272:
273: if (newObject instanceof Configurable) {
274: String id = atts.getValue(Constants.ID_ATTRIBUTE_NAME);
275: if (id == null || id.equals(""))
276: id = interfaceName + instanceName
277: + componentCount++;
278: if (containerComponents.size() > 0) {
279: id = ((Component) containerComponents.peek())
280: .getId()
281: + Constants.ID_DELIMITER + id;
282: }
283: try {
284: Configuration config = new Configuration(atts);
285: config.add(Constants.ID_ATTRIBUTE_NAME, id);
286: ((Configurable) newObject).configure(config);
287: } catch (Exception e) {
288: throw new SAXException(
289: "Component configuration problem", e);
290: }
291: }
292:
293: if (newObject instanceof ComponentAspect) {
294: try {
295: ((ComponentAspect) newObject)
296: .setComponent((Component) components.peek());
297: } catch (EmptyStackException e) {
298: throw new SAXException(
299: "trying to add a Component to a ComponentAspect, but components is empty.");
300: }
301: }
302: return newObject;
303: }
304: }
305: }
|