001    /*
002     * Copyright 2007 - 2009 JEuclid, http://jeuclid.sf.net
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    /* $Id: JEuclidElementFactory.java,v 550ea09de912 2010/08/05 17:05:27 max $ */
018    
019    package net.sourceforge.jeuclid.elements;
020    
021    import java.lang.reflect.Constructor;
022    import java.lang.reflect.Field;
023    import java.lang.reflect.InvocationTargetException;
024    import java.util.HashMap;
025    import java.util.Map;
026    
027    import net.sourceforge.jeuclid.elements.content.semantic.Annotation;
028    import net.sourceforge.jeuclid.elements.content.semantic.Semantics;
029    import net.sourceforge.jeuclid.elements.generic.ForeignElement;
030    import net.sourceforge.jeuclid.elements.generic.MathImpl;
031    import net.sourceforge.jeuclid.elements.presentation.enlivening.Maction;
032    import net.sourceforge.jeuclid.elements.presentation.general.Menclose;
033    import net.sourceforge.jeuclid.elements.presentation.general.Merror;
034    import net.sourceforge.jeuclid.elements.presentation.general.Mfenced;
035    import net.sourceforge.jeuclid.elements.presentation.general.Mfrac;
036    import net.sourceforge.jeuclid.elements.presentation.general.Mpadded;
037    import net.sourceforge.jeuclid.elements.presentation.general.Mphantom;
038    import net.sourceforge.jeuclid.elements.presentation.general.Mroot;
039    import net.sourceforge.jeuclid.elements.presentation.general.Mrow;
040    import net.sourceforge.jeuclid.elements.presentation.general.Msqrt;
041    import net.sourceforge.jeuclid.elements.presentation.general.Mstyle;
042    import net.sourceforge.jeuclid.elements.presentation.script.Mmultiscripts;
043    import net.sourceforge.jeuclid.elements.presentation.script.Mover;
044    import net.sourceforge.jeuclid.elements.presentation.script.Mprescripts;
045    import net.sourceforge.jeuclid.elements.presentation.script.Msub;
046    import net.sourceforge.jeuclid.elements.presentation.script.Msubsup;
047    import net.sourceforge.jeuclid.elements.presentation.script.Msup;
048    import net.sourceforge.jeuclid.elements.presentation.script.Munder;
049    import net.sourceforge.jeuclid.elements.presentation.script.Munderover;
050    import net.sourceforge.jeuclid.elements.presentation.script.None;
051    import net.sourceforge.jeuclid.elements.presentation.table.Maligngroup;
052    import net.sourceforge.jeuclid.elements.presentation.table.Malignmark;
053    import net.sourceforge.jeuclid.elements.presentation.table.Mlabeledtr;
054    import net.sourceforge.jeuclid.elements.presentation.table.Mtable;
055    import net.sourceforge.jeuclid.elements.presentation.table.Mtd;
056    import net.sourceforge.jeuclid.elements.presentation.table.Mtr;
057    import net.sourceforge.jeuclid.elements.presentation.token.Mglyph;
058    import net.sourceforge.jeuclid.elements.presentation.token.Mi;
059    import net.sourceforge.jeuclid.elements.presentation.token.Mn;
060    import net.sourceforge.jeuclid.elements.presentation.token.Mo;
061    import net.sourceforge.jeuclid.elements.presentation.token.Ms;
062    import net.sourceforge.jeuclid.elements.presentation.token.Mspace;
063    import net.sourceforge.jeuclid.elements.presentation.token.Mtext;
064    
065    import org.apache.batik.dom.AbstractDocument;
066    import org.apache.commons.logging.Log;
067    import org.apache.commons.logging.LogFactory;
068    import org.w3c.dom.Document;
069    import org.w3c.dom.Element;
070    
071    /**
072     * Creates MathElements from given element strings.
073     * 
074     * @version $Revision: 550ea09de912 $
075     */
076    public final class JEuclidElementFactory {
077    
078        /**
079         * Logger for this class
080         */
081        private static final Log LOGGER = LogFactory
082                .getLog(JEuclidElementFactory.class);
083    
084        private static final Map<String, Constructor<? extends JEuclidElement>> IMPL_CLASSES = new HashMap<String, Constructor<? extends JEuclidElement>>();;
085    
086        private JEuclidElementFactory() {
087            // Empty on purpose
088        }
089    
090        private static String removeNSPrefix(final String qualifiedName) {
091            final int posSeparator = qualifiedName.indexOf(':');
092            if (posSeparator >= 0) {
093                return qualifiedName.substring(posSeparator + 1);
094            }
095            return qualifiedName;
096        }
097    
098        /**
099         * Retrieve the constructor for an JEuclidElement, if available.
100         * 
101         * @param nsUri
102         *            namespace of the element
103         * @param qualifiedName
104         *            qualified name
105         * @return A constructor to create the element, or null if no such
106         *         constructor is available.
107         */
108        public static Constructor<? extends JEuclidElement> getJEuclidElementConstructor(
109                final String nsUri, final String qualifiedName) {
110            final String localName = JEuclidElementFactory
111                    .removeNSPrefix(qualifiedName);
112            if ((nsUri == null) || (nsUri.length() == 0)
113                    || (AbstractJEuclidElement.URI.equals(nsUri))) {
114                return JEuclidElementFactory.IMPL_CLASSES.get(localName);
115            } else {
116                return null;
117            }
118        }
119    
120        /**
121         * Factory for MathML Elements.
122         * 
123         * @param nsUri
124         *            namespace URI. May be null. May be ignored in the case of
125         *            MathML.
126         * @param qualifiedName
127         *            name of the element with optional namespace prefix.
128         * @param ownerDocument
129         *            Document this element belongs to.
130         * @return A new MathElement for this tag name.
131         */
132        public static Element elementFromName(final String nsUri,
133                final String qualifiedName, final Document ownerDocument) {
134    
135    
136            JEuclidElement element = null;
137    
138                final Constructor<? extends JEuclidElement> con = JEuclidElementFactory.
139                getJEuclidElementConstructor(nsUri, qualifiedName);
140    
141                if (con != null) {
142                    try {
143                        element = con.newInstance(qualifiedName,
144                                ownerDocument);
145                    } catch (final InstantiationException e) {
146                        element = null;
147                    } catch (final IllegalAccessException e) {
148                        element = null;
149                    } catch (final InvocationTargetException e) {
150                        element = null;
151                    }
152                }
153            
154            if (element == null) {
155                element = new ForeignElement(nsUri, qualifiedName,
156                        (AbstractDocument) ownerDocument);
157            }
158            return element;
159        }
160    
161        private static void addClass(final Class<? extends JEuclidElement> c) {
162            try {
163                final Field f = c.getField("ELEMENT");
164                final String tag = (String) f.get(null);
165                JEuclidElementFactory.IMPL_CLASSES.put(tag, c.getConstructor(
166                        String.class, AbstractDocument.class));
167            } catch (final NoSuchFieldException e) {
168                JEuclidElementFactory.LOGGER.warn(c.toString(), e);
169            } catch (final NoSuchMethodException e) {
170                JEuclidElementFactory.LOGGER.warn(c.toString(), e);
171            } catch (final IllegalAccessException e) {
172                JEuclidElementFactory.LOGGER.warn(c.toString(), e);
173            }
174        }
175    
176        // CHECKSTYLE:OFF
177        static {
178            // CHECKSTYLE:ON
179            JEuclidElementFactory.addClass(MathImpl.class);
180            JEuclidElementFactory.addClass(Mfenced.class);
181            JEuclidElementFactory.addClass(Mfrac.class);
182            JEuclidElementFactory.addClass(Menclose.class);
183            JEuclidElementFactory.addClass(Mphantom.class);
184            JEuclidElementFactory.addClass(Msup.class);
185            JEuclidElementFactory.addClass(Msub.class);
186            JEuclidElementFactory.addClass(Mmultiscripts.class);
187            JEuclidElementFactory.addClass(Mprescripts.class);
188            JEuclidElementFactory.addClass(None.class);
189            JEuclidElementFactory.addClass(Msubsup.class);
190            JEuclidElementFactory.addClass(Munder.class);
191            JEuclidElementFactory.addClass(Mover.class);
192            JEuclidElementFactory.addClass(Munderover.class);
193            JEuclidElementFactory.addClass(Mspace.class);
194            JEuclidElementFactory.addClass(Ms.class);
195            JEuclidElementFactory.addClass(Mstyle.class);
196            JEuclidElementFactory.addClass(Msqrt.class);
197            JEuclidElementFactory.addClass(Mroot.class);
198            JEuclidElementFactory.addClass(Mtable.class);
199            JEuclidElementFactory.addClass(Mtr.class);
200            JEuclidElementFactory.addClass(Mlabeledtr.class);
201            JEuclidElementFactory.addClass(Mtd.class);
202            JEuclidElementFactory.addClass(Mo.class);
203            JEuclidElementFactory.addClass(Mi.class);
204            JEuclidElementFactory.addClass(Mn.class);
205            JEuclidElementFactory.addClass(Mtext.class);
206            JEuclidElementFactory.addClass(Mrow.class);
207            JEuclidElementFactory.addClass(Maligngroup.class);
208            JEuclidElementFactory.addClass(Malignmark.class);
209            JEuclidElementFactory.addClass(Semantics.class);
210            JEuclidElementFactory.addClass(Annotation.class);
211            JEuclidElementFactory.addClass(Mpadded.class);
212            JEuclidElementFactory.addClass(Merror.class);
213            JEuclidElementFactory.addClass(Maction.class);
214            JEuclidElementFactory.addClass(Mglyph.class);
215        }
216    
217    }