1   /*
2    * LinearDefinition.java
3    *
4    * Copyright (c) 2002, The University of Sheffield.
5    *
6    * This file is part of GATE (see http://gate.ac.uk/), and is free
7    * software, licenced under the GNU Library General Public License,
8    * Version 2, June1991.
9    *
10   * A copy of this licence is included in the distribution in the file
11   * licence.html, and is also available at http://gate.ac.uk/gate/licence.html.
12   *
13   * borislav popov 02/2002
14   *
15   */
16  package gate.creole.gazetteer;
17  
18  import java.net.*;
19  import java.util.*;
20  import java.io.*;
21  import gate.creole.*;
22  
23  
24  /** Represents a Linear Definition [lists.def] file <br>
25   *  The normal usage of the class will be
26   *  * construct it
27   *  * setURL
28   *  * load
29   *  * change
30   *  * store
31   */
32  public class LinearDefinition extends gate.creole.AbstractLanguageResource
33                                implements List {
34  
35    /** the default encoding of the definition */
36    private final static String ENCODING = "UTF-8";
37  
38    /** the list of nodes */
39    private List nodes = new ArrayList();
40  
41    /** the URL of the definition */
42    private URL url;
43  
44    /** set of lists as strings*/
45    private List lists = new ArrayList();
46  
47    /**the encoding of the list */
48    private String encoding = "UTF-8";
49  
50    /** a mapping between a list and a node */
51    private Map nodesByList = new HashMap();
52  
53    /** a map of gazetteer lists by nodes. this is loaded on loadLists*/
54    private Map gazListsByNode = new HashMap();
55  
56    /** flag whether the definition has been modified after loading */
57    private boolean isModified = false;
58  
59    public LinearDefinition() {
60    }
61  
62    /** Sets the encoding of the linear def
63     *  @param encod the encoding to be set */
64    public void setEncoding(String encod) {
65      encoding = encod;
66    }
67  
68    /** Gets the encoding of the linear def
69     *  @return the encoding of the list*/
70    public String getEncoding() {
71      return encoding;
72    }
73  
74    /**
75     * Loads the gazetteer lists and maps them to the nodes
76     * @return a map of nodes vs GazetteerLists
77     * @throws ResourceInstantiationException
78     */
79    public Map loadLists() throws ResourceInstantiationException {
80      try {
81        gazListsByNode = new HashMap();
82        Iterator inodes = nodes.iterator();
83        while (inodes.hasNext()) {
84          LinearNode node = (LinearNode)inodes.next();
85  
86          GazetteerList list = new GazetteerList();
87          URL lurl = new URL(url,node.getList());
88          list.setURL(lurl);
89          list.setEncoding(encoding);
90          list.load();
91  
92          gazListsByNode.put(node,list);
93        } // while inodes
94      } catch (Exception ex) {
95        throw new ResourceInstantiationException(ex);
96      }
97      return gazListsByNode;
98    }  // loadLists()
99  
100   /** Loads a single gazetteer list given a name
101    *  @param listName the name of the list to be loaded
102    *  @return the loaded gazetteer list
103    *  @throws ResourceInstantiationException*/
104   public GazetteerList loadSingleList(String listName)
105   throws ResourceInstantiationException {
106     GazetteerList list = new GazetteerList();
107     try {
108       URL turl = url;
109       if (-1 != url.getProtocol().indexOf("gate")) {
110         turl = gate.util.protocols.gate.Handler.class.getResource(
111                       gate.util.Files.getResourcePath() + url.getPath()
112                     );
113       } // if gate:path url
114 
115 
116       try {
117         URL lurl = new URL(url,listName);
118         list.setURL(lurl);
119         list.load();
120       } catch (Exception x) {
121         String path = turl.getPath();
122         int slash = path.lastIndexOf("/");
123         if (-1 != slash ) {
124           path = path.substring(0,slash+1);
125         }
126 
127         File f = new File(path+listName);
128 
129         if (!f.exists())
130           f.createNewFile();
131 
132         URL lurl = new URL(url,listName);
133         list.setURL(lurl);
134         list.load();
135 
136       }
137 
138 
139 
140     } catch (MalformedURLException murle ) {
141       throw new ResourceInstantiationException(murle);
142     } catch (IOException ioex) {
143       throw new ResourceInstantiationException(ioex);
144     }
145     return list;
146   } // loadSingleList
147 
148   /**Gets the lists by node map
149    * @return a map of nodes vs lists*/
150   public Map getListsByNode(){
151     return gazListsByNode;
152   }
153 
154   /** Gets a map of lists names vs nodes
155    *  @return a map of lists names vs nodes*/
156   public Map getNodesByListNames() {
157      return nodesByList;
158   }
159 
160   /**Gets the value of the isModified flag.
161    * @return true if the definition has been modified    */
162   public boolean  isModified() {
163     return isModified;
164   }
165 
166   /**Gets the url of this linear definition
167    * @return the url of this linear definition   */
168   public URL getURL() {
169     return url;
170   }
171 
172 
173   /**Sets the url of this linear definition
174    * @param aUrl the url of this linear definition   */
175   public void setURL(URL aUrl) {
176     url = aUrl;
177   }
178 
179   /**
180    * Loads linear definition if url is set
181    */
182   public void load() throws ResourceInstantiationException {
183     if (null == url) {
184       throw new ResourceInstantiationException("URL not set (null).");
185     }
186     try {
187       BufferedReader defReader =
188       new BufferedReader(new InputStreamReader((url).openStream(), ENCODING));
189 
190       String line;
191       LinearNode node;
192       while (null != (line = defReader.readLine())) {
193         node = new LinearNode(line);
194         this.add(node);
195       } //while
196 
197       defReader.close();
198       isModified = false;
199     } catch (Exception x){
200       throw new ResourceInstantiationException(x);
201     }
202   } // load();
203 
204   /**
205    * Stores this to a definition file.
206    */
207   public void store() throws ResourceInstantiationException{
208     if (null == url) {
209       throw new ResourceInstantiationException("URL not set.(null)");
210     }
211     try {
212       URL tempUrl = url;
213       if (-1 != url.getProtocol().indexOf("gate")) {
214         tempUrl = gate.util.protocols.gate.Handler.class.getResource(
215                       gate.util.Files.getResourcePath() + url.getPath()
216                     );
217       } // if gate:path url
218 
219       File fileo = new File(tempUrl.getFile());
220       fileo.delete();
221       BufferedWriter defWriter = new BufferedWriter(new FileWriter(fileo));
222       Iterator inodes = nodes.iterator();
223       while (inodes.hasNext()) {
224         defWriter.write(inodes.next().toString());
225         defWriter.newLine();
226       }
227       defWriter.close();
228       isModified = false;
229     } catch(Exception x) {
230       throw new ResourceInstantiationException(x);
231     }
232 
233   } // store();
234 
235   /**
236    * Gets gazetteer lists of this definition.
237    * note that a new list is created so the adding and removing of lists will
238    * not affect the internal members. Also there is no setLists method since the leading
239    * member of the class is nodes, and lists cannot be added individually without being
240    * associated with a node.
241    * @return a list of the gazetteer lists names
242    */
243   public List getLists() {
244     return new ArrayList(lists);
245   }
246 
247   /** get the nodes of the definition as a list
248    *  @return the list of nodes */
249   public List getNodes() {
250     return new ArrayList(nodes);
251   }
252 
253 
254   /** Gets the set of all major types in this definition
255    * @return the set of all major types present in this definition*/
256   public Set getMajors() {
257     Set result = new HashSet();
258     for ( int i = 0 ; i < nodes.size() ; i++ )
259     {
260       String maj = ((LinearNode)nodes.get(i)).getMajorType();
261       if (null!= maj)
262         result.add(maj);
263     }
264     return result;
265   } // getMajors
266 
267   /** Gets the set of all minor types in this definition
268    * @return the set of all minor types present in this definition*/
269   public Set getMinors() {
270     Set result = new HashSet();
271     for ( int i = 0 ; i < nodes.size() ; i++ ) {
272       String min = ((LinearNode)nodes.get(i)).getMinorType();
273       if (null!=min)
274         result.add(min);
275     }
276     result.add("");
277     return result;
278   } // getMinors()
279 
280   /** Gets the set of all languages in this definition
281    * @return the set of all languages present in this definition*/
282   public Set getLanguages() {
283     Set result = new HashSet();
284     for ( int i = 0 ; i < nodes.size() ; i++ ) {
285       String lang = ((LinearNode)nodes.get(i)).getLanguage();
286       if (null!=lang)
287         result.add(lang);
288     }
289     result.add("");
290     return result;
291   } // getMinors()
292 
293 
294   /*---implementation of interface java.util.List---*/
295   public boolean addAll(int index, Collection c) {
296     int size = nodes.size();
297     Iterator iter = c.iterator();
298     Object o;
299     while (iter.hasNext()) {
300       o = iter.next();
301       if (o instanceof LinearNode)  {
302         add(index,o);
303       } // instance of linearnode
304     } // while
305 
306     boolean result = (size != nodes.size());
307     isModified |= result;
308     return result;
309   }
310 
311   public Object get(int index) {
312     return nodes.get(index);
313   }
314 
315   public Object set(int index, Object element) {
316     throw new UnsupportedOperationException("this method has not been implemented");
317   }
318 
319   public void add(int index, Object o) {
320     if (o instanceof LinearNode) {
321       String list = ((LinearNode)o).getList();
322       if (!nodesByList.containsKey(list)) {
323         try {
324           GazetteerList gl = loadSingleList(list);
325           gazListsByNode.put(o,gl);
326           nodes.add(index,o);
327           nodesByList.put(list,o);
328           lists.add(list);
329           isModified = true;
330         } catch (ResourceInstantiationException x) {
331           // do nothing since the list ain't real
332         }
333       } // if unique
334     } // if a linear node
335   }
336 
337   public Object remove(int index) {
338     Object result = null;
339     int size = nodes.size();
340     result = nodes.remove(index);
341     if (null!=result) {
342       String list = ((LinearNode)result).getList();
343       lists.remove(list);
344       nodesByList.remove(list);
345       gazListsByNode.remove(result);
346       isModified |= (size != nodes.size());
347     }
348     return result;
349   }
350 
351   public int indexOf(Object o) {
352     return nodes.indexOf(o);
353   }
354 
355   public int lastIndexOf(Object o) {
356     return nodes.lastIndexOf(o);
357   }
358 
359   public ListIterator listIterator() {
360     throw new UnsupportedOperationException("this method is not implemented");
361   }
362 
363   public ListIterator listIterator(int index) {
364     throw new UnsupportedOperationException("this method is not implemented");
365   }
366 
367   public List subList(int fromIndex, int toIndex) {
368     return nodes.subList(fromIndex,toIndex);
369   } // class SafeIterator
370 
371   public int size() {
372     return nodes.size();
373   }
374 
375   public boolean isEmpty() {
376     return 0 == nodes.size();
377   }
378 
379   public boolean contains(Object o) {
380     return nodes.contains(o);
381   }
382 
383   public Iterator iterator() {
384     return new SafeIterator();
385   }
386 
387   public Object[] toArray() {
388     return nodes.toArray();
389   }
390 
391   public Object[] toArray(Object[] a) {
392     return nodes.toArray(a);
393   }
394 
395   /**
396    * adds a new node, only if its list is new and uniquely mapped to this node.
397    * @param o a node
398    * @return true if the list of node is not already mapped with another node.
399    */
400   public boolean add(Object o) {
401     boolean result = false;
402     if (o instanceof LinearNode) {
403       String list = ((LinearNode)o).getList();
404       if (!nodesByList.containsKey(list)) {
405         try {
406           GazetteerList gl = loadSingleList(list);
407           gazListsByNode.put(o,gl);
408           result = nodes.add(o);
409           nodesByList.put(list,o);
410           lists.add(list);
411           isModified=true;
412         } catch (ResourceInstantiationException x) {
413           result = false;
414         }
415       } // if unique
416     } // if a linear node
417     return result;
418   } // add()
419 
420   public boolean remove(Object o) {
421     boolean result = false;
422     int size = nodes.size();
423     if (o instanceof LinearNode) {
424       result = nodes.remove(o);
425       String list = ((LinearNode)o).getList();
426       lists.remove(list);
427       nodesByList.remove(list);
428       gazListsByNode.remove(o);
429       isModified |= (size != nodes.size());
430     } // if linear node
431     return result;
432   }// remove
433 
434   public boolean containsAll(Collection c) {
435     return nodes.containsAll(c);
436   }
437 
438   public boolean addAll(Collection c) {
439     boolean result = false;
440     Iterator iter = c.iterator();
441     Object o;
442     while (iter.hasNext()) {
443       o = iter.next();
444       if (o instanceof LinearNode)  {
445         result |= add(o);
446       } // instance of linearnode
447     } // while
448     return result;
449   } // addAll()
450 
451 
452   public boolean removeAll(Collection c) {
453     boolean result = false;
454     Iterator iter = c.iterator();
455     Object o;
456     while (iter.hasNext()) {
457       o = iter.next();
458       result |= remove(o);
459     }
460     return result;
461   }// removeAll()
462 
463 
464   public boolean retainAll(Collection c) {
465     int aprioriSize = nodes.size();
466     List scrap = new ArrayList();
467 
468     LinearNode node;
469     Iterator inodes = nodes.iterator();
470     while(inodes.hasNext()) {
471       node = (LinearNode) inodes.next();
472       if (c.contains(node)) {
473         scrap.add(node);
474       }
475     } //for
476 
477     removeAll(scrap);
478     isModified |= (aprioriSize != nodes.size());
479     return (aprioriSize != nodes.size());
480   }
481 
482 
483   public void clear() {
484     nodes.clear();
485     lists.clear();
486     nodesByList.clear();
487     gazListsByNode.clear();
488     isModified = true;
489   }
490 
491   public boolean equals(Object o) {
492     boolean result = false;
493     if ( o instanceof LinearDefinition ) {
494       LinearDefinition def = (LinearDefinition) o;
495       result &= nodes.equals(def.nodes);
496       result &= lists.equals(def.lists);
497       result &= nodesByList.equals(def.lists);
498     }// if
499     return result;
500   } // equals()
501 
502  /*---end of implementation of interface java.util.List---*/
503 
504 
505 
506 
507 
508  /*-----------internal classes -------------*/
509 
510  /**SafeIterator class provides an iterator which is safe to be iterated and objects removed from it*/
511   private class SafeIterator implements Iterator {
512     private Iterator iter = LinearDefinition.this.nodes.iterator();
513     private boolean removeCalled = false;
514     private Object last = null;
515 
516     public boolean hasNext() {
517       return iter.hasNext();
518     }
519 
520     public Object next() {
521       removeCalled = false;
522       last = iter.next();
523       return last;
524     }
525 
526     public void remove() {
527       if (!removeCalled && null!=last ) {
528         LinearDefinition.this.remove(last);
529       }// if possible remove
530       removeCalled = true;
531     } // remove
532 
533   } // class SafeIterator
534 
535 
536 } // class LinearDefinition