source: java/main/src/main/java/com/framsticks/parsers/Schema.java @ 87

Last change on this file since 87 was 87, checked in by psniegowski, 11 years ago

HIGHLIGHTS:

  • FramsClass? and contained Param are now immutable classes (like String),

which allows to refer to them concurrently without synchronization
(which for example in turn simplifies GUI management)

  • also make Path immutable (which was earlier only assumed)
  • add global cache for FramsClasses? created solely and automatically

on base of Java classes.

representations basing on given FramsClass?

  • above changes greatly improved GUI responsivness during browsing
  • furtherly improve Param class hierarchy
  • allow to inject actions on state changes into MultiParamLoader?
  • add more tests

CHANGELOG:

Add StatusListener? to MultiParamLoader?.

Minor refactorization in MultiParamLoader?.

First step with auto append.

Add SchemaTest?.

Improve Registry.

Clean up in Registry.

Work out Registry.

Use annotations for Param.

Fix ListChange?.

Improve fluent interface of the FramsClassBuilder?.

Done caching of ReflectionAccess?.Backend

Fix hashCode of Pair.

A step on a way to cache ReflectionAccess?.Backend

Make SimpleAbstractAccess?.framsClass a final field.

Add static cache for FramsClasses? based on java.

Only classes created strictly and automatically
based on java classes are using this cache.

Make all Params immutable.

Many improvement to make Param immutable.

Make PrimitiveParam? generic type.

Several changes to make Param immutable.

Make FramsClass? immutable.

Another improvement to Path immutability.

Several improvements to Path.

Improve PathTest?.

Configurarable MutabilityDetector?.

File size: 9.3 KB
Line 
1package com.framsticks.parsers;
2
3import java.io.IOException;
4import java.io.InputStream;
5import java.util.Collections;
6import java.util.HashMap;
7import java.util.Map;
8
9import com.framsticks.params.*;
10import com.framsticks.params.annotations.AutoAppendAnnotation;
11import com.framsticks.params.annotations.FramsClassAnnotation;
12import com.framsticks.util.FramsticksException;
13import com.framsticks.util.lang.Numbers;
14import org.apache.log4j.Logger;
15
16import javax.xml.parsers.DocumentBuilder;
17import javax.xml.parsers.DocumentBuilderFactory;
18import javax.xml.parsers.ParserConfigurationException;
19
20import com.framsticks.leftovers.f0.NeuroClass;
21import org.w3c.dom.Document;
22import org.w3c.dom.NamedNodeMap;
23import org.w3c.dom.Node;
24import org.w3c.dom.NodeList;
25import org.xml.sax.SAXException;
26
27/**
28 * The Class Schema, which represent f0 schema (it contains all the possible
29 * classes definitions that can be used in f0 representation). Definitions are
30 * loaded from XML stream.
31 *
32 * @author Jarek Szymczak <name.surname@gmail.com>
33 * (please replace name and surname with my personal data)
34 */
35@FramsClassAnnotation
36public class Schema {
37
38        private final static Logger logger = Logger.getLogger(Schema.class);
39
40        protected final Registry registry = new Registry();
41
42        /** The neuro classes (classess representing different types of neurons). */
43        private Map<String, NeuroClass> neuroClasses = new HashMap<String, NeuroClass>();
44
45        public static InputStream getDefaultDefinitionAsStream() {
46                //return new FileInputStream(new File(Schema.class.getResource("/parsers/f0def.xml").getPath()));
47                return Schema.class.getResourceAsStream("/parsers/f0def.xml");
48        }
49
50        public Schema() {
51        }
52
53        @AutoAppendAnnotation
54        public void addNeuroClass(NeuroClass neuroClass) {
55        }
56
57        /**
58         * Instantiates a new schema.
59         *
60         * @param inputStream
61         *            the xml stream with schema
62         * @throws Exception
63         *             the exception if one occurred while reading the stream
64         */
65        public Schema(InputStream inputStream) {
66
67                DocumentBuilderFactory factory;
68                DocumentBuilder db;
69
70                try {
71                        factory = javax.xml.parsers.DocumentBuilderFactory.newInstance();
72                        db = factory.newDocumentBuilder();
73
74                        Document document = db.parse(inputStream);
75                        NodeList classes = document.getElementsByTagName("CLASS");
76
77                        for (int i = 0; i < classes.getLength(); i++) {
78                                Node classNode = classes.item(i);
79                                FramsClass framsClass = processClass(classNode);
80                                registry.putInfoIntoCache(framsClass);
81                        }
82
83                        classes = document.getElementsByTagName("NEUROCLASS");
84
85                        for (int i = 0; i < classes.getLength(); i++) {
86                                Node classNode = classes.item(i);
87                                FramsClass framsClass = processClass(classNode);
88
89                                NamedNodeMap attributes = classNode.getAttributes();
90                                int prefInputs = getIntAttribute(attributes, "INPUTS");
91                                int prefOutput = getIntAttribute(attributes, "OUTPUT");
92                                int prefLocation = getIntAttribute(attributes, "LOCATION");
93                                int visualHints = getIntAttribute(attributes, "VISUALHINTS");
94                                String symbolGlymphString = getAttribute(attributes, "SYMBOL");
95                                int[] symbolGlymph = null;
96
97                                if (symbolGlymphString != null) {
98                                        String[] sgha = symbolGlymphString.split(",");
99                                        int length = sgha.length;
100                                        symbolGlymph = new int[length];
101                                        for (int j = 0; j < length; j++) {
102                                                try {
103                                                        symbolGlymph[j] = Integer.parseInt(sgha[j]);
104                                                } catch (NumberFormatException e) {
105                                                        logger.error("an error occurred while parsing symbol glymph, class getId: "
106                                                                        + framsClass.getId()
107                                                                        + ", glymph offset: " + j);
108                                                }
109                                        }
110                                }
111
112                                neuroClasses.put(framsClass.getId(), new NeuroClass(
113                                                framsClass, prefInputs, prefOutput, prefLocation,
114                                                visualHints, symbolGlymph));
115                        }
116
117                } catch (IOException | ParserConfigurationException | SAXException e) {
118                        throw new FramsticksException().msg("unexpected exception occurred").cause(e);
119                }
120        }
121
122        /**
123         * Method used for convenience, it retrieves the Integer value stored in
124         * node under certain attribute getName. If value is not present or is other
125         * getType than integer 0 is returned.
126         *
127         * @return attribute value if value exists and it's integer (0 otherwise)
128         *
129         */
130        private static int getIntAttribute(NamedNodeMap attributes, String name) {
131                String v = getAttribute(attributes, name);
132                if (v == null) {
133                        return 0;
134                }
135                try {
136                        return Integer.parseInt(v);
137                } catch (NullPointerException e) {
138                        return 0;
139                } catch (NumberFormatException e) {
140                        logger.fatal("attribute " + name
141                                        + " should be numeric: " + v);
142                        return 0;
143                }
144        }
145
146        private static String getAttribute(NamedNodeMap attributes, String name) {
147                Node item = attributes.getNamedItem(name);
148                if (item == null) {
149                        return null;
150                }
151                return item.getNodeValue();
152        }
153
154        /**
155         * Method used for convenience, it retrieves the value stored in node under
156         * certain attribute getName. If value is not present method returns null.
157         *
158         * @param attributeName
159         *            the attribute getName
160         * @param node
161         *            the node
162         * @return attribute value if value exists (null otherwise)
163         *
164         */
165        private static String getAttributeFromNode(String attributeName, Node node) {
166                if (node == null) {
167                        return null;
168                }
169                return getAttribute(node.getAttributes(), attributeName);
170        }
171
172        /**
173         * In this method analysis of single class is performed.
174         *
175         * @param classNode
176         *            the class node
177         * @return the param entry list as a class schema
178         * @throws Exception
179         *             the exception in case of any error
180         */
181        private static FramsClass processClass(Node classNode) {
182                String classId = null;
183                String className = "";
184                String classDescription = "";
185                try {
186                        classId = classNode.getAttributes().getNamedItem("ID").getNodeValue();
187                } catch (NullPointerException e) {
188                        throw new FramsticksException().msg("class id is not defined");
189                }
190
191                className = getAttributeFromNode("NAME", classNode);
192                classDescription = getAttributeFromNode("DESCRIPTION", classNode);
193
194                FramsClassBuilder builder = FramsClass.build().id(classId).name(className).description(classDescription);
195
196                NodeList classProperties = classNode.getChildNodes();
197
198                for (int j = 0; j < classProperties.getLength(); j++) {
199                        Node node = classProperties.item(j);
200
201                        if ("GROUP".equals(node.getNodeName())) {
202                                NamedNodeMap attributes = node.getAttributes();
203                                String name = getAttribute(attributes, "NAME");
204                                if (name == null) {
205                                        logger.warn("Group name in class \"" + classId + "\" (" + className + ") is undefined");
206                                } else {
207                                        builder.group(new Group(name));
208                                }
209                        } else if ("PROP".equals(node.getNodeName())
210                                        || "NEUROPROP".equals(node.getNodeName())) {
211
212                                NamedNodeMap attributes = node.getAttributes();
213                                processParameter(attributes, classId, builder);
214                        }
215
216                }
217
218                return builder.finish();
219        }
220
221        private static <T extends Number> T extractAttribute(NamedNodeMap attributes, String name, Class<T> type) {
222                String value = getAttribute(attributes, name);
223                if (value == null) {
224                        return null;
225                }
226                return Numbers.parse(value, type);
227        }
228        /**
229         * It analyses the single property within the class
230         *
231         * @param attributes
232         *            the attributes of property
233         * @param classId
234         *            the class getId
235         * @return the param entry representing single parameter
236         * @throws Exception
237         *             the exception in case of any error
238         */
239        private static void processParameter(NamedNodeMap attributes, String classId, FramsClassBuilder classBuilder) {
240
241                String id = getAttribute(attributes, "ID");
242                if (id == null) {
243                        throw new FramsticksException().msg("Property ID in class \"" + classId + "\" is undefined");
244                }
245                String type = getAttribute(attributes, "TYPE");
246                if (type == null) {
247                        throw new FramsticksException().msg("TYPE of property \"" + id + "\" is undefined");
248                }
249
250                String name = getAttribute(attributes, "NAME");
251                String description = getAttribute(attributes, "DESCRIPTION");
252                int group = getIntAttribute(attributes, "GROUP");
253                String flagsString = getAttribute(attributes, "FLAGS");
254
255                Integer flags = 0;
256
257                try {
258                        if (flagsString != null)
259                                for (String flag : flagsString.split("[^0-9]")) {
260                                        if (flag.trim().equals(""))
261                                                continue;
262                                        flags |= Integer.parseInt(flag);
263                                }
264                } catch (NumberFormatException e) {
265                        logger.warn("FLAGS parameter should be an Integer value or separated Integer values. FLAGS are set to: "
266                                        + flags);
267                }
268
269                ParamBuilder builder = classBuilder.param(id).name(name).help(description).group(group).flags(flags);
270
271                builder.type(type);
272
273                if ("d".equals(type)) {
274                        builder.min(extractAttribute(attributes, "MIN", Integer.class));
275                        builder.max(extractAttribute(attributes, "MAX", Integer.class));
276                        builder.def(extractAttribute(attributes, "DEF", Integer.class));
277                } else if ("f".equals(type)) {
278                        builder.min(extractAttribute(attributes, "MIN", Double.class));
279                        builder.max(extractAttribute(attributes, "MAX", Double.class));
280                        builder.def(extractAttribute(attributes, "DEF", Double.class));
281                } else if ("s".equals(type)) {
282                        builder.min(extractAttribute(attributes, "MIN", Integer.class));
283                        builder.max(extractAttribute(attributes, "MAX", Integer.class));
284                        builder.def(extractAttribute(attributes, "DEF", Integer.class));
285                        builder.def(getAttribute(attributes, "DEF"));
286                } else {
287                        builder.type(type);
288                }
289
290                classBuilder.param(builder);
291        }
292
293
294        public Map<String, NeuroClass> getNeuroClasses() {
295                return Collections.unmodifiableMap(neuroClasses);
296        }
297
298        public final Registry getRegistry() {
299                return registry;
300        }
301
302
303}
Note: See TracBrowser for help on using the repository browser.