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