001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.dom;
020:
021: import java.util.Iterator;
022: import java.util.LinkedList;
023: import java.util.List;
024: import java.util.ListIterator;
025: import java.util.Locale;
026: import java.util.MissingResourceException;
027:
028: import org.apache.batik.css.engine.CSSContext;
029: import org.apache.batik.css.engine.CSSEngine;
030: import org.apache.batik.css.engine.value.ShorthandManager;
031: import org.apache.batik.css.engine.value.ValueManager;
032: import org.apache.batik.css.parser.ExtendedParser;
033: import org.apache.batik.css.parser.ExtendedParserWrapper;
034: import org.apache.batik.dom.util.DOMUtilities;
035: import org.apache.batik.dom.util.DoublyIndexedTable;
036: import org.apache.batik.i18n.Localizable;
037: import org.apache.batik.i18n.LocalizableSupport;
038: import org.apache.batik.util.Service;
039: import org.apache.batik.util.XMLResourceDescriptor;
040:
041: import org.w3c.css.sac.Parser;
042: import org.w3c.dom.DOMException;
043: import org.w3c.dom.Document;
044: import org.w3c.dom.Element;
045: import org.w3c.dom.css.DOMImplementationCSS;
046: import org.w3c.dom.css.ViewCSS;
047:
048: /**
049: * This class implements the {@link org.w3c.dom.DOMImplementation} interface.
050: * It allows the user to extend the set of elements supported by a
051: * Document, directly or through the Service API (see
052: * {@link org.apache.batik.util.Service}).
053: *
054: * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
055: * @version $Id: ExtensibleDOMImplementation.java 478249 2006-11-22 17:29:37Z dvholten $
056: */
057: public abstract class ExtensibleDOMImplementation extends
058: AbstractDOMImplementation implements DOMImplementationCSS,
059: StyleSheetFactory, Localizable {
060:
061: /**
062: * The custom elements factories.
063: */
064: protected DoublyIndexedTable customFactories;
065:
066: /**
067: * The custom value managers.
068: */
069: protected List customValueManagers;
070:
071: /**
072: * The custom shorthand value managers.
073: */
074: protected List customShorthandManagers;
075:
076: /**
077: * The error messages bundle class name.
078: */
079: protected static final String RESOURCES = "org.apache.batik.dom.resources.Messages";
080:
081: /**
082: * The localizable support for the error messages.
083: */
084: protected LocalizableSupport localizableSupport;
085:
086: /**
087: * Creates a new DOMImplementation.
088: */
089: public ExtensibleDOMImplementation() {
090: initLocalizable();
091:
092: Iterator iter = getDomExtensions().iterator();
093:
094: while (iter.hasNext()) {
095: DomExtension de = (DomExtension) iter.next();
096: de.registerTags(this );
097: }
098: }
099:
100: // Localizable //////////////////////////////////////////////////////
101:
102: /**
103: * Implements {@link Localizable#setLocale(Locale)}.
104: */
105: public void setLocale(Locale l) {
106: localizableSupport.setLocale(l);
107: }
108:
109: /**
110: * Implements {@link Localizable#getLocale()}.
111: */
112: public Locale getLocale() {
113: return localizableSupport.getLocale();
114: }
115:
116: protected void initLocalizable() {
117: localizableSupport = new LocalizableSupport(RESOURCES,
118: getClass().getClassLoader());
119: }
120:
121: /**
122: * Implements {@link Localizable#formatMessage(String,Object[])}.
123: */
124: public String formatMessage(String key, Object[] args)
125: throws MissingResourceException {
126: return localizableSupport.formatMessage(key, args);
127: }
128:
129: /**
130: * Allows the user to register a new element factory.
131: */
132: public void registerCustomElementFactory(String namespaceURI,
133: String localName, ElementFactory factory) {
134: if (customFactories == null) {
135: customFactories = new DoublyIndexedTable();
136: }
137: customFactories.put(namespaceURI, localName, factory);
138: }
139:
140: /**
141: * Allows the user to register a new CSS value manager.
142: */
143: public void registerCustomCSSValueManager(ValueManager vm) {
144: if (customValueManagers == null) {
145: customValueManagers = new LinkedList();
146: }
147: customValueManagers.add(vm);
148: }
149:
150: /**
151: * Allows the user to register a new shorthand CSS value manager.
152: */
153: public void registerCustomCSSShorthandManager(ShorthandManager sm) {
154: if (customShorthandManagers == null) {
155: customShorthandManagers = new LinkedList();
156: }
157: customShorthandManagers.add(sm);
158: }
159:
160: /**
161: * Creates new CSSEngine and attach it to the document.
162: */
163: public CSSEngine createCSSEngine(AbstractStylableDocument doc,
164: CSSContext ctx) {
165: String pn = XMLResourceDescriptor.getCSSParserClassName();
166: Parser p;
167: try {
168: p = (Parser) Class.forName(pn).newInstance();
169: } catch (ClassNotFoundException e) {
170: throw new DOMException(DOMException.INVALID_ACCESS_ERR,
171: formatMessage("css.parser.class",
172: new Object[] { pn }));
173: } catch (InstantiationException e) {
174: throw new DOMException(DOMException.INVALID_ACCESS_ERR,
175: formatMessage("css.parser.creation",
176: new Object[] { pn }));
177: } catch (IllegalAccessException e) {
178: throw new DOMException(DOMException.INVALID_ACCESS_ERR,
179: formatMessage("css.parser.access",
180: new Object[] { pn }));
181: }
182: ExtendedParser ep = ExtendedParserWrapper.wrap(p);
183:
184: ValueManager[] vms;
185: if (customValueManagers == null) {
186: vms = new ValueManager[0];
187: } else {
188: vms = new ValueManager[customValueManagers.size()];
189: Iterator it = customValueManagers.iterator();
190: int i = 0;
191: while (it.hasNext()) {
192: vms[i++] = (ValueManager) it.next();
193: }
194: }
195:
196: ShorthandManager[] sms;
197: if (customShorthandManagers == null) {
198: sms = new ShorthandManager[0];
199: } else {
200: sms = new ShorthandManager[customShorthandManagers.size()];
201: Iterator it = customShorthandManagers.iterator();
202: int i = 0;
203: while (it.hasNext()) {
204: sms[i++] = (ShorthandManager) it.next();
205: }
206: }
207:
208: CSSEngine result = createCSSEngine(doc, ctx, ep, vms, sms);
209: doc.setCSSEngine(result);
210: return result;
211: }
212:
213: public abstract CSSEngine createCSSEngine(
214: AbstractStylableDocument doc, CSSContext ctx,
215: ExtendedParser ep, ValueManager[] vms,
216: ShorthandManager[] sms);
217:
218: /**
219: * Creates a ViewCSS.
220: */
221: public abstract ViewCSS createViewCSS(AbstractStylableDocument doc);
222:
223: /**
224: * Implements the behavior of Document.createElementNS() for this
225: * DOM implementation.
226: */
227: public Element createElementNS(AbstractDocument document,
228: String namespaceURI, String qualifiedName) {
229: if (namespaceURI != null && namespaceURI.length() == 0) {
230: namespaceURI = null;
231: }
232: if (namespaceURI == null)
233: return new GenericElement(qualifiedName.intern(), document);
234:
235: if (customFactories != null) {
236: String name = DOMUtilities.getLocalName(qualifiedName);
237: ElementFactory cef;
238: cef = (ElementFactory) customFactories.get(namespaceURI,
239: name);
240: if (cef != null) {
241: return cef
242: .create(DOMUtilities.getPrefix(qualifiedName),
243: document);
244: }
245: }
246: return new GenericElementNS(namespaceURI.intern(),
247: qualifiedName.intern(), document);
248: }
249:
250: // The element factories /////////////////////////////////////////////////
251:
252: /**
253: * This interface represents a factory for elements.
254: */
255: public interface ElementFactory {
256: /**
257: * Creates an instance of the associated element type.
258: */
259: Element create(String prefix, Document doc);
260: }
261:
262: // Service /////////////////////////////////////////////////////////
263:
264: protected static List extensions = null;
265:
266: protected static synchronized List getDomExtensions() {
267: if (extensions != null)
268: return extensions;
269:
270: extensions = new LinkedList();
271:
272: Iterator iter = Service.providers(DomExtension.class);
273:
274: while (iter.hasNext()) {
275: DomExtension de = (DomExtension) iter.next();
276: float priority = de.getPriority();
277: ListIterator li = extensions.listIterator();
278: for (;;) {
279: if (!li.hasNext()) {
280: li.add(de);
281: break;
282: }
283: DomExtension lde = (DomExtension) li.next();
284: if (lde.getPriority() > priority) {
285: li.previous();
286: li.add(de);
287: break;
288: }
289: }
290: }
291:
292: return extensions;
293: }
294: }
|