OdfXMLFactory.java
/**
* **********************************************************************
*
* <p>DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* <p>Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
*
* <p>Use is subject to license terms.
*
* <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0. You can also obtain a copy of the License at
* http://odftoolkit.org/docs/license.txt
*
* <p>Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
*
* <p>See the License for the specific language governing permissions and limitations under the
* License.
*
* <p>**********************************************************************
*/
/*
* This file is automatically generated.
* Don't edit manually.
*/
package org.odftoolkit.odfdom.pkg;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.w3c.dom.DOMException;
/**
* This factory determines what elements are being used in the DOC layer (i.e. the convenient
* layer).
*
* <p>The mapping of ODF element to convenient class can be changed from the user during run time.
*
* <p>For example, a user might want to create a table always with a certain style or default data
* and might want to overwrite the mapping for <code>{odf.element table:table}</code>, that a
* different class instead of <code>OdfTable</code> is being used.
*/
public class OdfXMLFactory {
private static Map<OdfName, Class> mElementTypes = new HashMap<OdfName, Class>();
private static Map<OdfName, Class> mAttributeTypes = new HashMap<OdfName, Class>();
private static Map<String, String> mElementRenames = new HashMap<String, String>();
// a set for the element which need to load a none generated manual written class
private static Set<String> mHandwrittenElementClasses = new HashSet<String>();
private static final String LOCAL_NAME_DELIMITER = "-";
private static final String ELEMENT_NAME_DELIMITER = ":";
private static final String ELEMENT_PACKAGE_NAME = "element";
private static final String ATTRIBUTE_PACKAGE_NAME = "attribute";
static {
mElementRenames.put("text:h", "text:heading");
mElementRenames.put("text:p", "text:paragraph");
mHandwrittenElementClasses.add("draw:frame");
mHandwrittenElementClasses.add("draw:image");
mHandwrittenElementClasses.add("number:currency-style");
mHandwrittenElementClasses.add("number:date-style");
mHandwrittenElementClasses.add("number:percentage-style");
mHandwrittenElementClasses.add("number:number-style");
mHandwrittenElementClasses.add("number:time-style");
// Starting Refactoring. Goal: using XML DOM classes with sets for styles instead of own layer
// mHandwrittenElements.add("office:automatic-styles");
// mHandwrittenElements.add("office:master-styles");
// mHandwrittenElements.add("office:styles");
mHandwrittenElementClasses.add("style:default-style");
mHandwrittenElementClasses.add("style:style");
mHandwrittenElementClasses.add("style:page-layout");
mHandwrittenElementClasses.add("text:h");
mHandwrittenElementClasses.add("text:list");
mHandwrittenElementClasses.add("text:list-level-style-bullet");
mHandwrittenElementClasses.add("text:list-level-style-image");
mHandwrittenElementClasses.add("text:list-level-style-number");
mHandwrittenElementClasses.add("text:list-style");
mHandwrittenElementClasses.add("text:outline-level-style");
mHandwrittenElementClasses.add("text:outline-style");
mHandwrittenElementClasses.add("text:p");
mHandwrittenElementClasses.add("text:span");
}
/**
* @param odfName the name of the ODF attribute the desired DOM class should represent.
* @return the Java DOM attribute class to be mapped to a certain ODF attribute.
*/
private static Class getOdfAttributeClass(OdfName odfName) {
return getOdfNodeClass(odfName, ATTRIBUTE_PACKAGE_NAME, mAttributeTypes);
}
/**
* @param odfName the name of the ODF element the desired DOM class should represent.
* @return the Java DOM element class to be mapped to a certain ODF element.
*/
private static Class getOdfElementClass(OdfName odfName) {
return getOdfNodeClass(odfName, ELEMENT_PACKAGE_NAME, mElementTypes);
}
private static Class getOdfNodeClass(
OdfName odfName, String nodeType, Map<OdfName, Class> classCache) {
Class c = null;
String className = "";
c = classCache.get(odfName);
if (c == null) {
String prefix = odfName.getPrefix();
if (prefix != null && !(nodeType.equals(ATTRIBUTE_PACKAGE_NAME) && prefix.equals("xmlns"))) {
String qName = odfName.getQName();
String localName = odfName.getLocalName();
// judge whether the element need to load class from incubator package.
if (mHandwrittenElementClasses.contains(qName)) {
// judge whether the element need to rename before find class name.
if (mElementRenames.containsKey(qName)) {
String renameName = mElementRenames.get(qName);
StringTokenizer stok = new StringTokenizer(renameName, ELEMENT_NAME_DELIMITER);
prefix = stok.nextToken();
localName = stok.nextToken();
}
className = getOdfIncubatorNodeClassName(prefix, localName);
} else if ("manifest".equals(prefix)) {
className = getOdfPKGNodeClassName(prefix, localName, nodeType);
} else {
className = getOdfDOMNodeClassName(prefix, localName, nodeType);
}
try {
c = Class.forName(className);
classCache.put(odfName, c);
} catch (ClassNotFoundException ex) {
// all classes are first tring to load and warning is given later
} catch (NoClassDefFoundError dex) {
Logger.getLogger(OdfXMLFactory.class.getName())
.log(Level.FINER, "NoClassDefFoundError: " + className, dex.getMessage());
}
}
}
return c;
}
private static String getOdfIncubatorNodeClassName(String prefix, String localName) {
boolean contains = false;
StringBuilder className = new StringBuilder();
if (localName.indexOf(LOCAL_NAME_DELIMITER) != -1) {
StringTokenizer stok = new StringTokenizer(localName, LOCAL_NAME_DELIMITER);
while (stok.hasMoreElements()) {
String substr = stok.nextToken();
if (substr.equals(prefix)) {
contains = true;
}
className = className.append(toUpperCaseFirstCharacter(substr));
}
} else {
className = className.append(toUpperCaseFirstCharacter(localName));
}
if (!((contains && !localName.endsWith("table"))
|| (localName.equals(prefix))
|| (localName.startsWith(prefix) && prefix.equals("anim")))) {
className = className.insert(0, toUpperCaseFirstCharacter(prefix));
}
className = className.insert(0, "org.odftoolkit.odfdom.incubator.doc." + prefix + "." + "Odf");
return className.toString();
}
private static String getOdfPKGNodeClassName(String prefix, String localName, String nodeType) {
StringBuilder className = new StringBuilder("org.odftoolkit.odfdom.pkg." + prefix + ".");
if (localName.indexOf(LOCAL_NAME_DELIMITER) != -1) {
StringTokenizer stok = new StringTokenizer(localName, LOCAL_NAME_DELIMITER);
while (stok.hasMoreElements()) {
className = className.append(toUpperCaseFirstCharacter(stok.nextToken()));
}
} else {
className = className.append(toUpperCaseFirstCharacter(localName));
}
className.append(toUpperCaseFirstCharacter(nodeType));
return className.toString();
}
private static String getOdfDOMNodeClassName(String prefix, String localName, String nodeType) {
StringBuilder className =
new StringBuilder("org.odftoolkit.odfdom.dom." + nodeType + "." + prefix + ".");
className = className.append(toUpperCaseFirstCharacter(prefix));
if (localName.indexOf(LOCAL_NAME_DELIMITER) != -1) {
StringTokenizer stok = new StringTokenizer(localName, LOCAL_NAME_DELIMITER);
while (stok.hasMoreElements()) {
className = className.append(toUpperCaseFirstCharacter(stok.nextToken()));
}
} else {
className = className.append(toUpperCaseFirstCharacter(localName));
}
className.append(toUpperCaseFirstCharacter(nodeType));
return className.toString();
}
private static String toUpperCaseFirstCharacter(String token) {
return token.substring(0, 1).toUpperCase() + token.substring(1);
}
public static OdfElement newOdfElement(OdfFileDom dom, OdfName name) throws DOMException {
OdfElement element = null;
// lookup registered element class for qname
Class elementClass = getOdfElementClass(name);
// if a class was registered create an instance of that class
if (elementClass != null) {
element = (OdfElement) getNodeFromClass(dom, elementClass);
} else {
String oldPrefix = name.getPrefix();
if (oldPrefix != null) {
// check if the namespace prefix is correct or add potential namespace to DOM
OdfName adaptedName = addNamespaceToDom(name, dom);
String newPrefix = adaptedName.getPrefix();
// in case the prefix was changed as it existed before
if (oldPrefix != null
&& !oldPrefix.equals(newPrefix)
// "_1" is the suffix added by OdfFileDom to an existing Namespace
&& newPrefix.indexOf("__") == -1) {
// look up again if there is a class registered for this prefix
element = newOdfElement(dom, adaptedName);
} else {
element = (OdfElement) new OdfAlienElement(dom, adaptedName);
Logger.getLogger(OdfXMLFactory.class.getName())
.log(Level.FINER, "None-ODF element created for {0}", adaptedName.getQName());
}
} else {
element = (OdfElement) new OdfAlienElement(dom, name);
Logger.getLogger(OdfXMLFactory.class.getName())
.log(Level.FINER, "None-ODF element created for {0}", name.getQName());
}
}
return element;
}
public static OdfAttribute newOdfAttribute(OdfFileDom dom, OdfName name) throws DOMException {
OdfAttribute attr = null;
// lookup registered attribute class for qname
// SJ: but there exists elements & attributes having the same qName ("style:style")
// so it is not ensured to get a OdfAttribute ... in case of "style:style" you get a
// OdfStyle which is not a OdfAttribute :-(
Class attributeClass = getOdfAttributeClass(name);
// if a class was registered create an instance of that class
if (attributeClass != null) {
Object node = getNodeFromClass(dom, attributeClass);
if (node instanceof OdfAttribute) {
return (OdfAttribute) node;
}
}
// add a namespace unless it is a xmlns attribute (no attr value to set the uri)
String prefix = name.getPrefix();
if (prefix != null && !prefix.equals("xmlns")) {
// check if the namespace prefix is correct or add potential namespace to DOM
OdfName adaptedName = addNamespaceToDom(name, dom);
String newPrefix = adaptedName.getPrefix();
// in case the prefix was changed as it existed before
if (!prefix.equals(newPrefix) && newPrefix.indexOf("__") == -1) {
// look up again if there is a class registered for this prefix
attr = newOdfAttribute(dom, adaptedName);
} else {
attr = (OdfAttribute) new OdfAlienAttribute(dom, name);
Logger.getLogger(OdfXMLFactory.class.getName())
.log(Level.FINER, "None-ODF attribute created for {0}", adaptedName.getQName());
}
} else {
// create an alien attribute for namespace attribute "xmlns:*"
attr = (OdfAttribute) new OdfAlienAttribute(dom, name);
}
return attr;
}
private static OdfName addNamespaceToDom(OdfName name, OdfFileDom dom) {
OdfNamespace newNS = dom.setNamespace(name.getPrefix(), name.getUri());
return OdfName.newName(newNS, name.getLocalName());
}
/**
* @param dom the XML DOM file where the node should be created on.
* @param nodeClass being an XMLNode the Java class of the instance to be created.
* @return an object instance of the XML node class being provided (usually an attribute or
* element).
*/
static Object getNodeFromClass(OdfFileDom dom, Class nodeClass) {
Object o = null;
try {
Constructor ctor = nodeClass.getConstructor(new Class[] {OdfFileDom.class});
o = ctor.newInstance(new Object[] {dom});
} catch (Exception cause) {
// an exception at this point is a bug. Throw an Error
throw new Error("ODF DOM error in attribute factory", cause);
}
return o;
}
}