org.odftoolkit.odfdom.pkg.OdfXMLFactory Maven / Gradle / Ivy
Show all versions of odfdom-java Show documentation
/**
* **********************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
*
Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
*
*
Use is subject to license terms.
*
*
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
*
*
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.
*
*
See the License for the specific language governing permissions and limitations under the
* License.
*
*
**********************************************************************
*/
/*
* 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.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).
*
*
The mapping of ODF element to convenient class can be changed from the user during run time.
*
*
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 {odf.element table:table}
, that a
* different class instead of OdfTable
is being used.
*/
public class OdfXMLFactory {
private static Map mElementTypes = new HashMap();
private static Map mAttributeTypes = new HashMap();
private static final Map mElementRenames =
Map.of(
"text:h", "text:heading",
"text:p", "text:paragraph");
// a set for the element which need to load a none generated manual written class
private static final Set mHandwrittenElementClasses =
Set.of(
"draw:frame",
"draw:image",
"number:boolean-style",
"number:currency-style",
"number:date-style",
"number:percentage-style",
"number:number-style",
"number:text-style",
"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");
"style:default-style",
"style:style",
"style:page-layout",
"text:h",
"text:list",
"text:list-level-style-bullet",
"text:list-level-style-image",
"text:list-level-style-number",
"text:list-style",
"text:outline-level-style",
"text:outline-style",
"text:p",
"text:span");
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";
/**
* @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 classCache) {
Class c = null;
String className = "";
synchronized (classCache) {
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;
}
}