OSDN Git Service

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