001    /****************************************************************
002     * Licensed to the Apache Software Foundation (ASF) under one   *
003     * or more contributor license agreements.  See the NOTICE file *
004     * distributed with this work for additional information        *
005     * regarding copyright ownership.  The ASF licenses this file   *
006     * to you under the Apache License, Version 2.0 (the            *
007     * "License"); you may not use this file except in compliance   *
008     * with the License.  You may obtain a copy of the License at   *
009     *                                                              *
010     *   http://www.apache.org/licenses/LICENSE-2.0                 *
011     *                                                              *
012     * Unless required by applicable law or agreed to in writing,   *
013     * software distributed under the License is distributed on an  *
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015     * KIND, either express or implied.  See the License for the    *
016     * specific language governing permissions and limitations      *
017     * under the License.                                           *
018     ****************************************************************/
019    
020    package org.apache.james.jspf.impl;
021    
022    import org.apache.james.jspf.core.LogEnabled;
023    import org.apache.james.jspf.core.Logger;
024    import org.apache.james.jspf.core.exceptions.PermErrorException;
025    import org.apache.james.jspf.parser.TermDefinition;
026    import org.apache.james.jspf.parser.TermsFactory;
027    import org.apache.james.jspf.terms.Configuration;
028    import org.apache.james.jspf.terms.ConfigurationEnabled;
029    import org.apache.james.jspf.wiring.WiringService;
030    import org.apache.james.jspf.wiring.WiringServiceException;
031    import org.apache.james.jspf.wiring.WiringServiceTable;
032    
033    import java.io.IOException;
034    import java.io.InputStream;
035    import java.util.ArrayList;
036    import java.util.Collection;
037    import java.util.Collections;
038    import java.util.Properties;
039    
040    /**
041     * The default implementation of the TermsFactory
042     */
043    public class DefaultTermsFactory implements TermsFactory {
044        
045        private String termFile = "org/apache/james/jspf/parser/jspf.default.terms";
046        
047        private Collection<TermDefinition> mechanismsCollection;
048    
049        private Collection<TermDefinition> modifiersCollection;
050    
051        private Logger log;
052        
053        private WiringService wiringService;
054    
055        public DefaultTermsFactory(Logger log) {
056            this.log = log;
057            this.wiringService = new WiringServiceTable();
058            ((WiringServiceTable) this.wiringService).put(LogEnabled.class, log);
059            init();
060        }
061    
062        public DefaultTermsFactory(Logger log, WiringService wiringService) {
063            this.log = log;
064            this.wiringService = wiringService;
065            init();
066        }
067    
068        /**
069         * Initialize the factory and the services
070         */
071        private void init() {
072            try {
073                InputStream is = Thread.currentThread().getContextClassLoader()
074                        .getResourceAsStream(termFile);
075                if (is == null) {
076                    throw new NullPointerException("Unable to find the "+termFile+" resource in the classpath");
077                }
078                Properties p = new Properties();
079                p.load(is);
080                String mechs = p.getProperty("mechanisms");
081                String mods = p.getProperty("modifiers");
082                String[] classes;
083                classes = mechs.split(",");
084                Class<?>[] knownMechanisms = new Class[classes.length];
085                for (int i = 0; i < classes.length; i++) {
086                    log.debug("Add following class as known mechanismn: "
087                            + classes[i]);
088                    knownMechanisms[i] = Thread.currentThread()
089                            .getContextClassLoader().loadClass(classes[i]);
090                }
091                mechanismsCollection = createTermDefinitionCollection(knownMechanisms);
092                classes = mods.split(",");
093                Class<?>[] knownModifiers = new Class[classes.length];
094                for (int i = 0; i < classes.length; i++) {
095                    log.debug("Add following class as known modifier: "
096                            + classes[i]);
097                    knownModifiers[i] = Thread.currentThread()
098                            .getContextClassLoader().loadClass(classes[i]);
099                }
100                modifiersCollection = createTermDefinitionCollection(knownModifiers);
101        
102            } catch (IOException e) {
103                throw new IllegalStateException(
104                        "Term configuration cannot be found");
105            } catch (ClassNotFoundException e) {
106                throw new IllegalStateException(
107                        "One configured class cannot be found");
108            }
109        }
110    
111    
112        /**
113         * Create a collection of term definitions supported by this factory.
114         * 
115         * @param classes
116         *            classes to analyze
117         * @param staticFieldName
118         *            static field to concatenate
119         * @return map <Class,Pattern>
120         */
121        private Collection<TermDefinition> createTermDefinitionCollection(Class<?>[] classes) {
122            Collection<TermDefinition> l = new ArrayList<TermDefinition>();
123            for (int j = 0; j < classes.length; j++) {
124                try {
125                    l.add(new DefaultTermDefinition(classes[j]));
126                } catch (Exception e) {
127                    log.debug("Unable to create the term collection", e);
128                    throw new IllegalStateException(
129                            "Unable to create the term collection");
130                }
131            }
132            return Collections.synchronizedCollection(l);
133        }
134    
135    
136        /**
137         * @see org.apache.james.jspf.parser.TermsFactory#createTerm(java.lang.Class, org.apache.james.jspf.terms.Configuration)
138         */
139        public Object createTerm(Class<?> termDef, Configuration subres) throws PermErrorException, InstantiationException {
140            try {
141                Object term = termDef.newInstance();
142                
143                try {
144                    wiringService.wire(term);
145                } catch (WiringServiceException e) {
146                    throw new InstantiationException(
147                            "Unexpected error adding dependencies to term: " + e.getMessage());
148                }
149    
150                if (term instanceof ConfigurationEnabled) {
151                    if (subres == null || subres.groupCount() == 0) {
152                        ((ConfigurationEnabled) term).config(null);
153                    } else {
154                        ((ConfigurationEnabled) term).config(subres);
155                    }
156                }
157                return term;
158            } catch (IllegalAccessException e) {
159                throw new InstantiationException(
160                        "Unexpected error creating term: " + e.getMessage());
161            }
162        }
163    
164    
165        /**
166         * @see org.apache.james.jspf.parser.TermsFactory#getMechanismsCollection()
167         */
168        public Collection<TermDefinition> getMechanismsCollection() {
169            return mechanismsCollection;
170        }
171    
172    
173        /**
174         * @see org.apache.james.jspf.parser.TermsFactory#getModifiersCollection()
175         */
176        public Collection<TermDefinition> getModifiersCollection() {
177            return modifiersCollection;
178        }
179    
180    }