001package org.maltparser.core.feature.system;
002
003import java.io.IOException;
004import java.io.InputStream;
005import java.net.MalformedURLException;
006import java.net.URL;
007
008import javax.xml.parsers.DocumentBuilder;
009import javax.xml.parsers.DocumentBuilderFactory;
010import javax.xml.parsers.ParserConfigurationException;
011
012import org.maltparser.core.exception.MaltChainedException;
013import org.maltparser.core.feature.FeatureException;
014import org.maltparser.core.feature.FeatureRegistry;
015import org.maltparser.core.feature.function.Function;
016import org.maltparser.core.helper.HashMap;
017import org.maltparser.core.helper.URLFinder;
018import org.maltparser.core.plugin.Plugin;
019import org.maltparser.core.plugin.PluginLoader;
020import org.w3c.dom.Element;
021import org.w3c.dom.NodeList;
022import org.xml.sax.SAXException;
023/**
024 *  
025 *
026 * @author Johan Hall
027 * @since 1.0
028**/
029public class FeatureEngine extends HashMap<String, FunctionDescription> {
030        public final static long serialVersionUID = 3256444702936019250L;
031        
032        public FeatureEngine() {
033                super();
034        }
035
036        public Function newFunction(String functionName, FeatureRegistry registry) throws MaltChainedException {
037                int i = 0;
038                Function func = null;
039                while (true) {
040                        FunctionDescription funcDesc = get(functionName + "~~" + i);
041                        if (funcDesc == null) {
042                                break;
043                        }
044                        func = funcDesc.newFunction(registry);
045                        if (func != null) {
046                                break;
047                        }
048                        i++;
049                }
050                return func;
051        }
052        
053        public void load(String urlstring) throws MaltChainedException {
054                final URLFinder f = new URLFinder();
055                load(f.findURL(urlstring));
056        }
057        
058        public void load(PluginLoader plugins) throws MaltChainedException {
059                 for (Plugin plugin : plugins) {
060                        URL url = null;
061                        try {
062                                url = new URL("jar:"+plugin.getUrl() + "!/appdata/plugin.xml");
063                        } catch (MalformedURLException e) {
064                                throw new FeatureException("Malformed URL: 'jar:"+plugin.getUrl() + "!plugin.xml'", e);
065                        }
066                        try { 
067                                InputStream is = url.openStream();
068                                is.close();
069                        } catch (IOException e) {
070                                continue;
071                        }
072
073                        load(url);
074                }
075        }
076        
077        public void load(URL specModelURL) throws MaltChainedException {
078        try {
079            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
080            DocumentBuilder db = dbf.newDocumentBuilder();
081            Element root = null;
082
083            root = db.parse(specModelURL.openStream()).getDocumentElement();
084
085            if (root == null) {
086                throw new FeatureException("The feature system file '"+specModelURL.getFile()+"' cannot be found. ");
087            }
088            
089            readFeatureSystem(root);
090        } catch (IOException e) {
091                throw new FeatureException("The feature system file '"+specModelURL.getFile()+"' cannot be found. ", e);
092        } catch (ParserConfigurationException e) {
093                throw new FeatureException("Problem parsing the file "+specModelURL.getFile()+". ", e);
094        } catch (SAXException e) {
095                throw new FeatureException("Problem parsing the file "+specModelURL.getFile()+". ", e);
096        }
097        }
098        
099        public void readFeatureSystem(Element system) throws MaltChainedException {
100                NodeList functions = system.getElementsByTagName("function");
101                for (int i = 0; i < functions.getLength(); i++) {
102                        readFunction((Element)functions.item(i));
103                }
104        }
105        
106        public void readFunction(Element function) throws MaltChainedException {
107                boolean hasSubFunctions = function.getAttribute("hasSubFunctions").equalsIgnoreCase("true");
108                
109                boolean hasFactory = false;
110                if (function.getAttribute("hasFactory").length() > 0) {
111                        hasFactory = function.getAttribute("hasFactory").equalsIgnoreCase("true");
112                }
113                Class<?> clazz = null;
114                try {
115                        if (PluginLoader.instance() != null) {
116                                clazz = PluginLoader.instance().getClass(function.getAttribute("class"));
117                        }
118                        if (clazz == null) {
119                                clazz = Class.forName(function.getAttribute("class"));
120                        }
121                } catch (ClassNotFoundException e) { 
122                        throw new FeatureException("The feature system could not find the function class"+function.getAttribute("class")+".", e);
123                }
124                if (hasSubFunctions) {
125                        NodeList subfunctions = function.getElementsByTagName("subfunction");
126                        for (int i = 0; i < subfunctions.getLength(); i++) {
127                                readSubFunction((Element)subfunctions.item(i), clazz, hasFactory);
128                        }
129                } else {
130                        int i = 0;
131                        String n = null;
132                        while (true) {
133                                n = function.getAttribute("name") + "~~" + i;
134                                if (!containsKey(n)) {
135                                        break;
136                                }
137                                i++;
138                        }
139                        put(n, new FunctionDescription(function.getAttribute("name"), clazz, false, hasFactory));
140                }
141        }
142        
143        public void readSubFunction(Element subfunction, Class<?> clazz, boolean hasFactory) throws MaltChainedException {
144                int i = 0;
145                String n = null;
146                while (true) {
147                        n = subfunction.getAttribute("name") + "~~" + i;
148                        if (!containsKey(n)) {
149                                break;
150                        }
151                        i++;
152                }
153                put(n, new FunctionDescription(subfunction.getAttribute("name"), clazz, true, hasFactory));
154        }
155
156        public boolean equals(Object obj) {
157                if (this == obj)
158                        return true;
159                if (obj == null)
160                        return false;
161                if (getClass() != obj.getClass())
162                        return false;
163                if (this.size() != ((FeatureEngine)obj).size()) {
164                        return false;
165                }
166                for (String name : keySet()) {
167                        if (!get(name).equals(((FeatureEngine)obj).get(name))) {
168                                return false;
169                        }
170                }
171                return true;
172        }
173
174        public String toString() {
175                final StringBuilder sb = new StringBuilder();
176                for (String name : keySet()) {
177                        sb.append(name);
178                        sb.append('\t');
179                        sb.append(get(name));
180                        sb.append('\n');
181                }
182                return sb.toString();
183        }
184}