001/*
002 * Copyright (c) 2004-2012, Willem Cazander
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification, are permitted provided
006 * that the following conditions are met:
007 * 
008 * * Redistributions of source code must retain the above copyright notice, this list of conditions and the
009 *   following disclaimer.
010 * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
011 *   the following disclaimer in the documentation and/or other materials provided with the distribution.
012 * 
013 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
014 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
015 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
016 * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
018 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
019 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
020 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
021 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
022 */
023
024package org.x4o.xml.element;
025
026import java.util.List;
027import java.util.Map;
028import java.util.HashMap;
029import java.util.ArrayList;
030import java.util.logging.Logger;
031
032import javax.el.ELContext;
033import javax.el.ExpressionFactory;
034
035import org.x4o.xml.core.X4OPhase;
036import org.x4o.xml.core.config.X4OLanguageConfiguration;
037
038/**
039 * An AbstractElementLanguage.
040 * 
041 * @author Willem Cazander
042 * @version 1.0 Aug 20, 2005
043 */
044public abstract class AbstractElementLanguage implements ElementLanguageLocal {
045
046        private Logger logger = null;
047        private ExpressionFactory expressionFactory = null;
048        private ELContext eLContext = null;
049        private ElementAttributeValueParser elementAttributeValueParser = null;
050        private ElementObjectPropertyValue elementObjectPropertyValue = null;
051        private X4OPhase currentX4OPhase = null;
052        private Map<Element, X4OPhase> dirtyElements = null;
053        private Element rootElement = null;
054        private X4OLanguageConfiguration languageConfiguration = null;
055        private List<ElementLanguageModule> elementLanguageModules = null;
056
057        /**
058         * Creates a new empty ElementLanguage.
059         */
060        public AbstractElementLanguage() {
061                logger = Logger.getLogger(AbstractElementLanguage.class.getName());
062                logger.finest("Creating new ParsingContext");
063                elementLanguageModules = new ArrayList<ElementLanguageModule>(20);
064                currentX4OPhase = X4OPhase.FIRST_PHASE;
065                dirtyElements = new HashMap<Element, X4OPhase>(40);
066        }
067        
068        /**
069         * @see org.x4o.xml.element.ElementLanguage#getELContext()
070         */
071        public ELContext getELContext() {
072                return eLContext;
073        }
074
075        /**
076         * @see org.x4o.xml.element.ElementLanguageLocal#setELContext(javax.el.ELContext)
077         */
078        public void setELContext(ELContext context) {
079                if (eLContext!=null) {
080                        throw new IllegalStateException("Can only set elContext once.");
081                }
082                eLContext = context;
083        }
084
085        /**
086         * @see org.x4o.xml.element.ElementLanguage#getExpressionFactory()
087         */
088        public ExpressionFactory getExpressionFactory() {
089                return expressionFactory;
090        }
091
092        /**
093         * @see org.x4o.xml.element.ElementLanguageLocal#setExpressionFactory(javax.el.ExpressionFactory)
094         */
095        public void setExpressionFactory(ExpressionFactory expressionFactory) {
096                if (this.expressionFactory!=null) {
097                        throw new IllegalStateException("Can only set expressionFactory once.");
098                }
099                this.expressionFactory = expressionFactory;
100        }
101        
102        /**
103         * @return the elementAttributeValueParser
104         */
105        public ElementAttributeValueParser getElementAttributeValueParser() {
106                return elementAttributeValueParser;
107        }
108
109        /**
110         * @param elementAttributeValueParser the elementAttributeValueParser to set
111         */
112        public void setElementAttributeValueParser(ElementAttributeValueParser elementAttributeValueParser) {
113                if (this.elementAttributeValueParser!=null) {
114                        throw new IllegalStateException("Can only set elementAttributeValueParser once.");
115                }
116                this.elementAttributeValueParser = elementAttributeValueParser;
117        }
118
119        /**
120         * @return the elementObjectPropertyValue
121         */
122        public ElementObjectPropertyValue getElementObjectPropertyValue() {
123                return elementObjectPropertyValue;
124        }
125
126        /**
127         * @param elementObjectPropertyValue the elementObjectPropertyValue to set
128         */
129        public void setElementObjectPropertyValue(ElementObjectPropertyValue elementObjectPropertyValue) {
130                if (this.elementObjectPropertyValue!=null) {
131                        throw new IllegalStateException("Can only set elementObjectPropertyValue once.");
132                }
133                this.elementObjectPropertyValue = elementObjectPropertyValue;
134        }
135
136        /**
137         * @see org.x4o.xml.element.ElementLanguage#getCurrentX4OPhase()
138         */
139        public X4OPhase getCurrentX4OPhase() {
140                return currentX4OPhase;
141        }
142
143        /**
144         * @see org.x4o.xml.element.ElementLanguage#setCurrentX4OPhase(org.x4o.xml.core.X4OPhase)
145         */
146        public void setCurrentX4OPhase(X4OPhase currentX4OPhase) {
147                this.currentX4OPhase = currentX4OPhase;
148        }
149
150        /**
151         * @see org.x4o.xml.element.ElementLanguage#addDirtyElement(org.x4o.xml.element.Element, org.x4o.xml.core.X4OPhase)
152         */
153        public void addDirtyElement(Element element, X4OPhase phase) {
154                if (dirtyElements.containsKey(element)) {
155                        throw new IllegalArgumentException("Can't add an element twice.");
156                }
157                dirtyElements.put(element,phase);
158        }
159
160        /**
161         * @see org.x4o.xml.element.ElementLanguage#getDirtyElements()
162         */
163        public Map<Element, X4OPhase> getDirtyElements() {
164                return dirtyElements;
165        }
166
167        /**
168         * @see org.x4o.xml.element.ElementLanguage#getRootElement()
169         */
170        public Element getRootElement() {
171                return rootElement;
172        }
173
174        /**
175         * @see org.x4o.xml.element.ElementLanguage#setRootElement(org.x4o.xml.element.Element)
176         */
177        public void setRootElement(Element element) {
178                if (element==null) {
179                        throw new NullPointerException("May not set rootElement to null");
180                }
181                // allowed for reusing this context in multiple parse sessions.
182                //if (rootElement!=null) {
183                //      throw new IllegalStateException("Can't set rootElement when it is already set.");
184                //}
185                rootElement=element;
186        }
187
188        /**
189         * @return the languageConfiguration
190         */
191        public X4OLanguageConfiguration getLanguageConfiguration() {
192                return languageConfiguration;
193        }
194
195        /**
196         * @param languageConfiguration the languageConfiguration to set
197         */
198        public void setLanguageConfiguration(X4OLanguageConfiguration languageConfiguration) {
199                this.languageConfiguration = languageConfiguration;
200        }
201
202        /**
203         * @see org.x4o.xml.element.ElementLanguage#addElementLanguageModule(org.x4o.xml.element.ElementLanguageModule)
204         */
205        public void addElementLanguageModule(ElementLanguageModule elementLanguageModule) {
206                if (elementLanguageModule.getId()==null) {
207                        throw new NullPointerException("Can't add module without id.");
208                }
209                elementLanguageModules.add(elementLanguageModule);
210        }
211
212        /**
213         * @see org.x4o.xml.element.ElementLanguage#getElementLanguageModules()
214         */
215        public List<ElementLanguageModule> getElementLanguageModules() {
216                return elementLanguageModules;
217        }
218        
219
220        /**
221         * @see org.x4o.xml.element.ElementLanguage#findElementBindingHandlers(java.lang.Object,java.lang.Object)
222         */
223        public List<ElementBindingHandler> findElementBindingHandlers(Object parent,Object child) {
224                List<ElementBindingHandler> result = new ArrayList<ElementBindingHandler>(50);
225                for (int i=0;i<elementLanguageModules.size();i++) {
226                        ElementLanguageModule module = elementLanguageModules.get(i);
227                        findElementBindingHandlerInList(parent,child,result,module.getElementBindingHandlers());
228                }
229                for (ElementInterface ei:findElementInterfaces(parent)) {
230                        findElementBindingHandlerInList(parent,child,result,ei.getElementBindingHandlers());
231                }
232                return result;
233        }
234
235        private void findElementBindingHandlerInList(Object parent,Object child,List<ElementBindingHandler> result,List<ElementBindingHandler> checkList) {
236                for (ElementBindingHandler binding:checkList) {
237                        boolean parentBind = false;
238                        if (parent instanceof Class) {
239                                parentBind = binding.getBindParentClass().isAssignableFrom((Class<?>)parent);
240                        } else {
241                                parentBind = binding.getBindParentClass().isInstance(parent);
242                        }
243                        if (parentBind==false) {
244                                continue;
245                        }
246                        boolean childBind = false;
247                        for (Class<?> childClass:binding.getBindChildClasses()) {
248                                if (child instanceof Class && childClass.isAssignableFrom((Class<?>)child)) {
249                                        childBind=true;
250                                        break;  
251                                } else if (childClass.isInstance(child)) {
252                                        childBind=true;
253                                        break;
254                                }
255                        }
256                        if (parentBind & childBind) {
257                                result.add(binding);
258                        }
259                }       
260        }
261        
262        /**
263         * @see org.x4o.xml.element.ElementLanguage#findElementInterfaces(java.lang.Object)
264         */
265        public List<ElementInterface> findElementInterfaces(Object elementObject) {
266                if (elementObject==null) {
267                        throw new NullPointerException("Can't search for null object.");
268                }
269                List<ElementInterface> result = new ArrayList<ElementInterface>(50);
270                for (int i=0;i<elementLanguageModules.size();i++) {
271                        ElementLanguageModule module = elementLanguageModules.get(i);
272                        for (ElementInterface ei:module.getElementInterfaces()) {
273                                Class<?> eClass = ei.getInterfaceClass();
274                                logger.finest("Checking interface handler: "+ei+" for class: "+eClass);
275                                if (elementObject instanceof Class && eClass.isAssignableFrom((Class<?>)elementObject)) {
276                                        logger.finer("Found interface match from class; "+elementObject);
277                                        result.add(ei);
278                                } else if (eClass.isInstance(elementObject)) {
279                                        logger.finer("Found interface match from object; "+elementObject);
280                                        result.add(ei);
281                                }
282                        }
283                }
284                return result;
285        }
286
287        /**
288         * @see org.x4o.xml.element.ElementLanguage#findElementNamespaceContext(java.lang.String)
289         */
290        public ElementNamespaceContext findElementNamespaceContext(String namespaceUri) {
291                
292                // TODO: refactor so no search for every tag !!
293                ElementNamespaceContext result = null;
294                for (int i=0;i<elementLanguageModules.size();i++) {
295                        ElementLanguageModule module = elementLanguageModules.get(i);
296                        result = module.getElementNamespaceContext(namespaceUri);
297                        if (result!=null) {
298                                return result;
299                        }
300                }
301                return result;
302        }
303}