blob: 50f3b984a12b975e8a84c104d4598f18949c4d33 [file] [log] [blame]
/************************************************************************
*
* 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.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
* (ie. 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 <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 class from incubator package.
private static Set<String> mIncubatorElements = 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");
mIncubatorElements.add("draw:frame");
mIncubatorElements.add("draw:image");
mIncubatorElements.add("number:currency-style");
mIncubatorElements.add("number:date-style");
mIncubatorElements.add("number:percentage-style");
mIncubatorElements.add("number:number-style");
mIncubatorElements.add("number:time-style");
mIncubatorElements.add("office:automatic-styles");
mIncubatorElements.add("office:master-styles");
mIncubatorElements.add("office:styles");
mIncubatorElements.add("style:default-style");
mIncubatorElements.add("style:style");
mIncubatorElements.add("style:page-layout");
mIncubatorElements.add("text:h");
mIncubatorElements.add("text:list");
mIncubatorElements.add("text:list-level-style-bullet");
mIncubatorElements.add("text:list-level-style-image");
mIncubatorElements.add("text:list-level-style-number");
mIncubatorElements.add("text:list-style");
mIncubatorElements.add("text:outline-level-style");
mIncubatorElements.add("text:outline-style");
mIncubatorElements.add("text:p");
mIncubatorElements.add("text:span");
}
/** Mapping an ODF element to a new Java DOM element class.
* Note: There is a default class for each element being generated from the latest ODF schema
*/
private static void setOdfElementClass(OdfName odfName, Class className) {
mElementTypes.put(odfName, className);
}
/** Mapping an ODF attribute to a new Java DOM attribute class.
* Note: There is a default class for each element being generated from the latest ODF schema. */
private static void setOdfAttributeClass(OdfName odfName, Class className) {
mAttributeTypes.put(odfName, className);
}
/**
* @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, true);
}
/**
* @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, false);
}
private static Class getOdfNodeClass(OdfName odfName, String nodeType, Map<OdfName, Class> classCache, boolean isAttribute) {
Class c = null;
String className = "";
c = classCache.get(odfName);
if (c == null) {
// Ignore looking for XML namespace attributes or ODF elements without prefix,
// as there are no typed ODF classes
// (NOTE: For any ODF node from the schema the ODF prefix would ALWAYS exist
// as there is a prefix normalization during the previous loading)
String prefix = odfName.getPrefix();
if (prefix != null && !(isAttribute && prefix.equals("xmlns"))) {
String qName = odfName.getQName();
String localName = odfName.getLocalName();
//judge whether the element need to load class from incubator package.
if (mIncubatorElements.contains(qName) && !isAttribute) {
//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.INFO, "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.FINE, "None-ODF element created for {0}", adaptedName.getQName());
}
} else {
element = (OdfElement) new OdfAlienElement(dom, name);
Logger.getLogger(OdfXMLFactory.class.getName()).log(Level.FINE, "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
Class attributeClass = getOdfAttributeClass(name);
// if a class was registered create an instance of that class
if (attributeClass != null) {
attr = (OdfAttribute) getNodeFromClass(dom, attributeClass);
} else { // in case it is not a default ODF
// 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.FINE, "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 (usally 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;
}
}