OSDN Git Service

remove Revision tag
[stigmata/stigmata.git] / src / main / java / jp / sourceforge / stigmata / result / XmlFileExtractionResultSet.java
1 package jp.sourceforge.stigmata.result;
2
3 /*
4  * $Id$
5  */
6
7 import java.io.BufferedReader;
8 import java.io.File;
9 import java.io.FileNotFoundException;
10 import java.io.FileReader;
11 import java.io.FileWriter;
12 import java.io.IOException;
13 import java.io.PrintWriter;
14 import java.net.MalformedURLException;
15 import java.net.URL;
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.Iterator;
19 import java.util.List;
20 import java.util.Map;
21
22 import javax.xml.namespace.QName;
23 import javax.xml.stream.XMLEventReader;
24 import javax.xml.stream.XMLInputFactory;
25 import javax.xml.stream.XMLStreamException;
26 import javax.xml.stream.events.EndElement;
27 import javax.xml.stream.events.StartElement;
28 import javax.xml.stream.events.XMLEvent;
29
30 import jp.sourceforge.stigmata.Birthmark;
31 import jp.sourceforge.stigmata.BirthmarkContext;
32 import jp.sourceforge.stigmata.BirthmarkElement;
33 import jp.sourceforge.stigmata.BirthmarkEnvironment;
34 import jp.sourceforge.stigmata.BirthmarkSet;
35 import jp.sourceforge.stigmata.BirthmarkStoreException;
36 import jp.sourceforge.stigmata.BirthmarkStoreTarget;
37 import jp.sourceforge.stigmata.ComparisonMethod;
38 import jp.sourceforge.stigmata.ExtractionTarget;
39 import jp.sourceforge.stigmata.ExtractionUnit;
40 import jp.sourceforge.stigmata.Stigmata;
41 import jp.sourceforge.stigmata.printer.xml.ExtractionResultSetXmlPrinter;
42 import jp.sourceforge.stigmata.spi.BirthmarkSpi;
43 import jp.sourceforge.stigmata.ui.swing.ExtensionFilter;
44 import jp.sourceforge.stigmata.utils.MultipleIterator;
45
46 /**
47  * This class manages extracted birthmarks as xml file.
48  * This instance do not use {@link ExtractionTarget <code>ExtractionTarget</code>}.
49  * 
50  * @author Haruaki Tamada
51  */
52 public class XmlFileExtractionResultSet extends AbstractExtractionResultSet{
53     private boolean addmode = true;
54     private File storeDirectory;
55     private Map<ExtractionTarget, XmlFile> files = new HashMap<ExtractionTarget, XmlFile>();
56
57     XmlFileExtractionResultSet(BirthmarkContext context){
58         super(context);
59     }
60
61     XmlFileExtractionResultSet(BirthmarkContext context, File storeDirectory){
62         super(context);
63         this.storeDirectory = storeDirectory;
64     }
65
66     public XmlFileExtractionResultSet(BirthmarkContext context, boolean tableType){
67         super(context, tableType);
68     }
69
70     public XmlFileExtractionResultSet(File directory){
71         super(Stigmata.getInstance().createContext());
72
73         addmode = false;
74         storeDirectory = directory;
75
76         BirthmarkContext context = getContext();
77         context.setStoreTarget(BirthmarkStoreTarget.XMLFILE);
78         if(files.containsKey(ExtractionTarget.TARGET_X) 
79             && files.containsKey(ExtractionTarget.TARGET_Y)){
80             context.setComparisonMethod(ComparisonMethod.ROUND_ROBIN_XY);
81         }
82         else{
83             context.setComparisonMethod(ComparisonMethod.ROUND_ROBIN_SAME_PAIR);
84         }
85
86         for(File file: storeDirectory.listFiles(new ExtensionFilter("xml"))){
87             String fileName = file.getName();
88             String name = fileName.substring(0, fileName.lastIndexOf('.'));
89             ExtractionTarget et = ExtractionTarget.valueOf(name);
90             if(et != null){
91                 files.put(et, new XmlFile(file, context, false));
92             }
93         }
94     }
95
96     @Override
97     public void addBirthmarkSet(ExtractionTarget target, BirthmarkSet set) throws BirthmarkStoreException{
98         if(addmode){
99             if(target == ExtractionTarget.TARGET_BOTH){
100                 throw new IllegalArgumentException("unknown target: " + target);
101             }
102             XmlFile xml = files.get(target);
103             if(xml == null){
104                 xml = new XmlFile(new File(getStoreDirectory(), target.name() + ".xml"), getContext());
105                 files.put(target, xml);
106             }
107             xml.addBirthmarkSet(set);
108         }
109         else{
110             throw new BirthmarkStoreException("destination is already closed.");
111         }
112     }
113
114     @Override
115     public Iterator<BirthmarkSet> birthmarkSets(ExtractionTarget target){
116         closeAllStream();
117
118         XmlFile xml = files.get(target);
119         Iterator<BirthmarkSet> iterator;
120         if(xml != null){
121             iterator = xml.birthmarkSets();
122         }
123         else if(target == ExtractionTarget.TARGET_BOTH){
124             MultipleIterator<BirthmarkSet> mi = new MultipleIterator<BirthmarkSet>();
125             boolean addflag = false;
126             if(files.containsKey(ExtractionTarget.TARGET_X)){
127                 addflag = true;
128                 mi.add(files.get(ExtractionTarget.TARGET_X).birthmarkSets());
129             }
130             if(files.containsKey(ExtractionTarget.TARGET_Y)){
131                 addflag = true;
132                 mi.add(files.get(ExtractionTarget.TARGET_Y).birthmarkSets());
133             }
134             if(!addflag && files.containsKey(ExtractionTarget.TARGET_XY)){
135                 mi.add(files.get(ExtractionTarget.TARGET_XY).birthmarkSets());
136             }
137             iterator = mi;
138         }
139         else{
140             iterator = null;
141         }
142
143         return iterator;
144     }
145
146     @Override
147     public int getBirthmarkSetSize(ExtractionTarget target){
148         int size = 0;
149         XmlFile xml = files.get(target);
150         if(xml != null){
151             size = xml.getBirthmarkSetSize();
152         }
153         else if(target == ExtractionTarget.TARGET_BOTH){
154             if(files.containsKey(ExtractionTarget.TARGET_X)){
155                 size += files.get(ExtractionTarget.TARGET_X).getBirthmarkSetSize();
156             }
157             if(files.containsKey(ExtractionTarget.TARGET_Y)){
158                 size += files.get(ExtractionTarget.TARGET_Y).getBirthmarkSetSize();
159             }
160             if(size == 0 && files.containsKey(ExtractionTarget.TARGET_XY)){
161                 size += files.get(ExtractionTarget.TARGET_XY).getBirthmarkSetSize();
162             }
163         }
164         return size;
165     }
166
167     @Override
168     public BirthmarkStoreTarget getStoreTarget(){
169         return BirthmarkStoreTarget.XMLFILE;
170     }
171
172     @Override
173     public void removeAllBirthmarkSets(ExtractionTarget target){
174         XmlFile xml = files.get(target);
175         if(xml != null){
176             xml.removeAllBirthmarkSets();
177         }
178         else if(target == ExtractionTarget.TARGET_BOTH){
179             for(XmlFile file: files.values()){
180                 file.removeAllBirthmarkSets();
181             }
182         }
183     }
184
185     @Override
186     public void removeBirthmarkSet(ExtractionTarget target, BirthmarkSet set){
187         XmlFile xml = files.get(target);
188         if(xml != null){
189             xml.removeBirthmarkSet(set);
190         }
191         else if(target == ExtractionTarget.TARGET_BOTH){
192             throw new IllegalArgumentException("unknown target: " + target);
193         }
194     }
195
196     private File getStoreDirectory(){
197         if(storeDirectory == null){
198             storeDirectory = new File(BirthmarkEnvironment.getStigmataHome(), "extracted_birthmarks/" + generateId());
199         }
200         if(!storeDirectory.exists()){
201             storeDirectory.mkdirs();
202         }
203         return storeDirectory;
204     }
205
206     private void closeAllStream(){
207         if(addmode){
208             addmode = false;
209             for(XmlFile file: files.values()){
210                 file.closeStream();
211             }
212         }
213     }
214
215     /**
216      * Iterator class for reading birthmark xml file by StAX.
217      * 
218      * @author Haruaki Tamada
219      */
220     private static class BirthmarkSetStAXIterator implements Iterator<BirthmarkSet>{
221         private XMLEventReader reader = null;
222         private BirthmarkSet nextObject;
223         private List<URL> validItems;
224         private BirthmarkEnvironment env;
225         private BirthmarkContext context;
226
227         public BirthmarkSetStAXIterator(File file, List<URL> validItems, BirthmarkContext context){
228             try{
229                 XMLInputFactory factory = XMLInputFactory.newInstance();
230                 BufferedReader in = new BufferedReader(new FileReader(file));
231                 reader = factory.createXMLEventReader(in);
232             } catch(FileNotFoundException e){
233             } catch(XMLStreamException e){
234             }
235             this.validItems = validItems;
236             this.context = context;
237             this.env = context.getEnvironment();
238             try{
239                 nextObject = findNext();
240             } catch(XMLStreamException e){
241                 e.printStackTrace();
242             }
243         }
244
245         @Override
246         public boolean hasNext(){
247             boolean flag = nextObject != null;
248             if(!flag){
249                 try{
250                     reader.close();
251                 } catch(XMLStreamException e){
252                     e.printStackTrace();
253                 }
254             }
255             return flag;
256         }
257
258         @Override
259         public BirthmarkSet next(){
260             BirthmarkSet next = nextObject;
261             try{
262                 nextObject = findNext();
263             } catch(XMLStreamException e){
264                 e.printStackTrace();
265             }
266             return next;
267         }
268
269         @Override
270         public void remove(){
271         }
272
273         private BirthmarkSet findNext() throws XMLStreamException{
274             BirthmarkSet nextObject = null;
275             do{
276                 nextObject = findNextImpl();
277             } while(nextObject != null && validItems != null && !validItems.contains(nextObject.getLocation()));
278             return nextObject;
279         }
280
281         private BirthmarkSet findNextImpl() throws XMLStreamException{
282             String className = null;
283             BirthmarkSet bs = null;
284             Birthmark birthmark = null;
285             BirthmarkSpi service = null;
286                 
287             while(reader.hasNext()){
288                 // XMLEvent event = reader.peek();
289                 XMLEvent event = reader.nextEvent();
290                 if(event.isStartElement()){
291                     StartElement se = event.asStartElement();
292                     String part = se.getName().getLocalPart();
293                     if(part.equals("unit")){
294                         ExtractionUnit unit = ExtractionUnit.valueOf(reader.getElementText());
295                         if(unit != null){
296                             context.setExtractionUnit(unit);
297                         }                        
298                     }
299                     else if(part.equals("birthmark-type")){
300                         String type = reader.getElementText();
301                         if(env.getService(type) != null){
302                             context.addBirthmarkType(type);
303                         }                        
304                     }
305                     else if(part.equals("name")){
306                         className = reader.getElementText();
307                     }
308                     else if(part.equals("location")){
309                         String location = reader.getElementText();
310                         if(className == null || location == null){
311                             throw new XMLStreamException("incompatible with definition");
312                         }
313                         try{
314                             URL url = new URL(location);
315                             bs = new BirthmarkSet(className, url);
316                         } catch(MalformedURLException e){
317                             e.printStackTrace();
318                         }
319                     }
320                     else if(part.equals("element")){
321                         if(service != null){
322                             BirthmarkElement be = service.buildBirthmarkElement(reader.getElementText());
323                             birthmark.addElement(be);
324                         }
325                     }
326                     else if(part.equals("birthmark")){
327                         String type = se.getAttributeByName(new QName("type")).getValue();
328                         service = env.getService(type);
329                         if(service != null){
330                             birthmark = service.buildBirthmark();
331                             bs.addBirthmark(birthmark);
332                         }
333                         else{
334                             birthmark = null;
335                         }
336                     }
337                 }
338                 else if(event.isEndElement()){
339                     EndElement ee = event.asEndElement();
340                     if(ee.getName().getLocalPart().equals("extracted-birthmark")){
341                         reader.nextEvent();
342                         break;
343                     }
344                 }
345                 // reader.nextEvent();
346             }
347             return bs;
348         }
349     }
350
351     /**
352      * This class represents a xml file about XmlFileExtractionResultSet.
353      * 
354      * @author Haruaki Tamada
355      */
356     private static class XmlFile{
357         private ExtractionResultSetXmlPrinter formatter;
358         private BirthmarkContext context;
359         private List<URL> addList = new ArrayList<URL>();
360         private int size;
361         private File file;
362         private PrintWriter out;
363
364         public XmlFile(File file, BirthmarkContext context){
365             this.file = file;
366             this.context = context;
367         }
368
369         public XmlFile(File file, BirthmarkContext context, boolean addflag){
370             this.file = file;
371             this.context = context;
372             if(!addflag){
373                 addList = null;
374             }
375         }
376
377         public void addBirthmarkSet(BirthmarkSet bs) throws BirthmarkStoreException{
378             if(formatter == null){
379                 try{
380                     out = new PrintWriter(new FileWriter(file));
381                     formatter = new ExtractionResultSetXmlPrinter();
382                     formatter.printHeader(out);
383                     out.printf("    <unit>%s</unit>%n", context.getExtractionUnit());
384                     out.printf("    <birthmark-types>%n");
385                     for(String type: context.getBirthmarkTypes()){
386                         out.printf("      <birthmark-type>%s</birthmark-type>%n", type);
387                     }
388                     out.printf("    </birthmark-types>%n");
389                     
390                 }catch(IOException e){
391                 }
392             }
393             if(out == null || formatter == null){
394                 throw new BirthmarkStoreException("destination is closed on some reason");
395             }
396             size++;
397             addList.add(bs.getLocation());
398             formatter.printBirthmarkSet(out, bs);
399         }
400
401         public Iterator<BirthmarkSet> birthmarkSets(){
402             return new BirthmarkSetStAXIterator(file, addList, context);
403         }
404
405         public void closeStream(){
406             if(formatter != null){
407                 formatter.printFooter(out);
408                 out.close();
409                 out = null;
410                 formatter = null;
411             }
412         }
413
414         public int getBirthmarkSetSize(){
415             if(size == 0){
416                 int s = 0;
417                 for(Iterator<BirthmarkSet> i = birthmarkSets(); i.hasNext(); ){
418                     i.next();
419                     s++;
420                 }
421                 size = s;
422             }
423             return size;
424         }
425
426         public void removeAllBirthmarkSets(){
427             file.delete();
428             size = 0;
429             addList.clear();            
430         }
431
432         public void removeBirthmarkSet(BirthmarkSet set){
433             boolean removeFlag = addList.remove(set.getLocation());
434             if(removeFlag){
435                 size--;
436             }
437         }
438     }
439 }