001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.xml.retriever.impl;
043:
044: import java.awt.event.ActionEvent;
045: import java.io.File;
046: import java.io.FileNotFoundException;
047: import java.io.IOException;
048: import java.net.URI;
049: import java.net.URISyntaxException;
050: import java.net.UnknownHostException;
051: import java.text.DateFormat;
052: import java.util.ArrayList;
053: import java.util.Date;
054: import java.util.HashMap;
055: import java.util.LinkedList;
056: import java.util.List;
057: import java.util.Map;
058: import java.util.Stack;
059: import java.util.StringTokenizer;
060: import javax.swing.AbstractAction;
061: import org.netbeans.api.progress.ProgressHandle;
062: import org.netbeans.api.progress.ProgressHandleFactory;
063: import org.netbeans.modules.xml.retriever.DocumentParserFactory;
064: import org.netbeans.modules.xml.retriever.DocumentTypeParser;
065: import org.netbeans.modules.xml.retriever.impl.IConstants;
066: import org.netbeans.modules.xml.retriever.RetrieveEntry;
067: import org.netbeans.modules.xml.retriever.RetrieverEngine;
068: import org.netbeans.modules.xml.retriever.impl.RetrieverTask;
069: import org.netbeans.modules.xml.retriever.impl.URLResourceRetriever;
070: import org.netbeans.modules.xml.xam.locator.CatalogModelException;
071: import org.netbeans.modules.xml.retriever.catalog.CatalogWriteModel;
072: import org.netbeans.modules.xml.retriever.catalog.CatalogWriteModelFactory;
073: import org.openide.DialogDisplayer;
074: import org.openide.NotifyDescriptor;
075: import org.openide.filesystems.FileObject;
076: import org.openide.filesystems.FileUtil;
077: import org.openide.util.Cancellable;
078: import org.openide.util.NbBundle;
079: import org.openide.windows.IOProvider;
080: import org.openide.windows.InputOutput;
081: import org.openide.windows.OutputWriter;
082:
083: /**
084: *
085: * @author girix
086: */
087: public class RetrieverEngineImpl extends RetrieverEngine {
088:
089: private LinkedList<RetrieveEntry> currentRetrievalList = new LinkedList<RetrieveEntry>();
090:
091: private File currentSaveRootFile = null;
092:
093: private File fixedSaveRootFolder = null;
094:
095: boolean startNewThread = true;
096:
097: private boolean showErrorPopup = true;
098:
099: public RetrieverEngineImpl(File fixedSaveRootFolder) {
100: this .fixedSaveRootFolder = fixedSaveRootFolder;
101: this .currentSaveRootFile = fixedSaveRootFolder;
102: }
103:
104: public RetrieverEngineImpl(File fixedSaveRootFolder,
105: boolean startNewThread) {
106: this .fixedSaveRootFolder = fixedSaveRootFolder;
107: this .currentSaveRootFile = fixedSaveRootFolder;
108: this .startNewThread = startNewThread;
109: }
110:
111: public boolean canShowErrorPopup() {
112: return showErrorPopup;
113: }
114:
115: public void setShowErrorPopup(boolean show) {
116: this .showErrorPopup = show;
117: }
118:
119: public void addResourceToRetrieve(RetrieveEntry rent) {
120: currentRetrievalList.add(rent);
121: }
122:
123: Thread taskThread = null;
124:
125: public void start() {
126: if (startNewThread) {
127: taskThread = new Thread(this );
128: taskThread.start();
129: } else {
130: run();
131: }
132: }
133:
134: boolean STOP_PULL = false;
135:
136: public void run() {
137: ProgressHandle ph = ProgressHandleFactory.createHandle(NbBundle
138: .getMessage(RetrieverEngineImpl.class,
139: "LBL_PROGRESSBAR_Retrieve_XML"),
140: new Cancellable() {
141: public boolean cancel() {
142: synchronized (RetrieverEngineImpl.this ) {
143: if (!RetrieverEngineImpl.this .STOP_PULL) {
144: RetrieverEngineImpl.this .STOP_PULL = true;
145: //taskThread.interrupt();
146: }
147: }
148: return true;
149: }
150: }, new AbstractAction() {
151: public void actionPerformed(ActionEvent e) {
152: getOPWindow().setOutputVisible(true);
153: getOPWindow().select();
154: }
155: });
156: ph.start();
157: ph.switchToIndeterminate();
158: try {
159: pullRecursively();
160: } finally {
161: ph.finish();
162: }
163: }
164:
165: boolean firstTime = true;
166: String firstAddressParentStr = null;
167:
168: private void pullRecursively() {
169: synchronized (RetrieverEngineImpl.class) {
170: while (!currentRetrievalList.isEmpty() && !STOP_PULL) {
171: //System.out.println(currentRetrievalList);
172: RetrieveEntry rent = currentRetrievalList.getFirst();
173: //System.out.println("###"+rent.toString());
174: currentRetrievalList.removeFirst();
175: RetrieverTask rt = new RetrieverTask(rent, this );
176:
177: if (firstTime) {
178: firstAddressParentStr = rent.getCurrentAddress()
179: .substring(
180: 0,
181: rent.getCurrentAddress()
182: .lastIndexOf("/"));
183: firstTime = false;
184: }
185:
186: updateDownloadingInfo(rent);
187:
188: HashMap<String, File> storedFileMap = null;
189: ;
190: try {
191: storedFileMap = rt.goGetIt();
192: } catch (URISyntaxException ex) {
193: //This might an error in the file. Ignore
194: //ex.printStackTrace();
195: handleException(rent, ex);
196: continue;
197: } catch (IOException ex) {
198: //This might have been thrown to indicate a cyclic reference.
199: //ex.printStackTrace();
200: handleException(rent, ex);
201: continue;
202: }
203:
204: if (!rent.isRecursive())
205: continue;
206:
207: if (storedFileMap == null) {
208: continue;
209: }
210: String effectiveSrcAddr = storedFileMap.keySet()
211: .iterator().next();
212: File storedFile = storedFileMap.get(effectiveSrcAddr);
213:
214: rent.setSaveFile(storedFile);
215: rent.setEffectiveAddress(effectiveSrcAddr);
216:
217: updateDownloadedInfo(rent);
218:
219: createCatalogIfRequired(rent);
220:
221: DocumentTypeParser dtp = DocumentParserFactory
222: .getParser(rent.getDocType());
223: List<String> this FileRefs = null;
224: ;
225: try {
226: this FileRefs = dtp
227: .getAllLocationOfReferencedEntities(storedFile);
228: //System.out.println("Parsed:"+storedFile+" Got:"+thisFileRefs);
229: } catch (Exception ex) {
230: //was not able to parse the doc. Currently ignore this.
231: //ex.printStackTrace();
232: continue;
233: }
234: for (String ref : this FileRefs) {
235: currentRetrievalList.addLast(new RetrieveEntry(
236: effectiveSrcAddr, ref, storedFile, null,
237: rent.getDocType(), rent.isRecursive()));
238: }
239: printList();
240: }
241: closeOPOuts();
242: }
243: }
244:
245: private void printList() {
246: for (RetrieveEntry rent : currentRetrievalList) {
247: //System.out.println("------"+rent);
248: }
249: }
250:
251: public File getCurrentSaveRootFile() {
252: return currentSaveRootFile;
253: }
254:
255: public void setCurrentSaveRootFile(File currentSaveRootFile) {
256: this .currentSaveRootFile = currentSaveRootFile;
257: }
258:
259: private String getCorrectFolderName(int folderIndex) {
260: StringTokenizer stok = new StringTokenizer(
261: firstAddressParentStr, "/");
262: Stack<String> stack = new Stack<String>();
263: while (stok.hasMoreTokens())
264: stack.push(stok.nextToken());
265: for (int i = 1; i < folderIndex; i++)
266: stack.pop();
267: return stack.pop();
268: }
269:
270: int currentPushCount = 0;
271: int previousPushCount = 0;
272:
273: public void pushDownRoot(int pushCount) {
274: File newTmpRoot = new File(currentSaveRootFile.getParent()
275: + File.separator + System.currentTimeMillis());
276: File leafFolder = newTmpRoot;
277: leafFolder.mkdirs();
278: for (int i = pushCount; i >= 2; i--) {
279: leafFolder = new File(leafFolder.toString()
280: + File.separator
281: + getCorrectFolderName(currentPushCount + i));
282: leafFolder.mkdirs();
283: }
284: leafFolder = new File(leafFolder.toString() + File.separator
285: + getCorrectFolderName(currentPushCount + 1));
286: File movedRoot = leafFolder;
287: //String rootFolderName = saveRootFile.getName();
288: while (!currentSaveRootFile.renameTo(movedRoot)) {
289: try {
290: Thread.sleep(500);
291: } catch (InterruptedException ex) {
292: }
293: }
294: while (!newTmpRoot.renameTo(currentSaveRootFile)) {
295: try {
296: Thread.sleep(500);
297: } catch (InterruptedException ex) {
298: }
299: }
300:
301: File newRoot = currentSaveRootFile;
302: for (int i = pushCount; i >= 1; i--)
303: newRoot = new File(newRoot.toString() + File.separator
304: + getCorrectFolderName(currentPushCount + i));
305: correctAllEntriesInTheList(newRoot);
306: previousPushCount = currentPushCount;
307: currentPushCount += pushCount;
308: }
309:
310: public File getNewFileForOld(File oldFile, int pushCount) {
311: File newRoot = currentSaveRootFile;
312: for (int i = pushCount; i >= 1; i--)
313: newRoot = new File(newRoot.toString() + File.separator
314: + getCorrectFolderName(previousPushCount + i));
315: String oldPath = oldFile.toString();
316: String newPath = new String(new StringBuffer(oldPath).replace(
317: 0, currentSaveRootFile.toString().length(), newRoot
318: .toString()));
319: File newFile = new File(newPath);
320: return newFile;
321: }
322:
323: private void correctAllEntriesInTheList(File newRoot) {
324: for (RetrieveEntry rent : currentRetrievalList) {
325: String oldPath = rent.getLocalBaseFile().toString();
326: String newPath = new String(new StringBuffer(oldPath)
327: .replace(0,
328: currentSaveRootFile.toString().length(),
329: newRoot.toString()));
330: File newLocalBaseFile = new File(newPath);
331: rent.setLocalBaseFile(newLocalBaseFile);
332: }
333: for (RetrieveEntry rent : retrievedList) {
334: String oldPath = rent.getSaveFile().toString();
335: String newPath = new String(new StringBuffer(oldPath)
336: .replace(0,
337: currentSaveRootFile.toString().length(),
338: newRoot.toString()));
339: File newLocalBaseFile = new File(newPath);
340: rent.setSaveFile(newLocalBaseFile);
341: }
342: }
343:
344: public File getFixedSaveRootFolder() {
345: return fixedSaveRootFolder;
346: }
347:
348: private void handleException(RetrieveEntry rent, Exception ex) {
349: if (audits == null)
350: audits = new HashMap<RetrieveEntry, Exception>();
351: audits.put(rent, ex);
352: //System.out.println(ex instanceof UnknownHostException);
353: if (ex instanceof UnknownHostException) {
354: String errorMess = NbBundle.getMessage(
355: RetrieverEngineImpl.class, "MSG_unknown_host_p1")
356: + ex.getLocalizedMessage()
357: + "\n"
358: + NbBundle.getMessage(RetrieverEngineImpl.class,
359: "MSG_unknownhost_p2");
360: outputError(errorMess);
361: if (showErrorPopup) {
362: NotifyDescriptor.Message ndm = new NotifyDescriptor.Message(
363: errorMess,
364: NotifyDescriptor.Message.ERROR_MESSAGE);
365: DialogDisplayer.getDefault().notify(ndm);
366: }
367: return;
368: }
369: if (ex instanceof URISyntaxException) {
370: String errorMess = ex.getLocalizedMessage();
371: outputError(errorMess);
372: if (showErrorPopup) {
373: NotifyDescriptor.Message ndm = new NotifyDescriptor.Message(
374: errorMess,
375: NotifyDescriptor.Message.ERROR_MESSAGE);
376: DialogDisplayer.getDefault().notify(ndm);
377: }
378: return;
379: }
380: if (ex instanceof FileNotFoundException) {
381: String errorMess = NbBundle.getMessage(
382: RetrieverEngineImpl.class, "MSG_unknown_file", ex
383: .getMessage());
384: outputError(errorMess);
385: if (showErrorPopup) {
386: NotifyDescriptor.Message ndm = new NotifyDescriptor.Message(
387: errorMess,
388: NotifyDescriptor.Message.ERROR_MESSAGE);
389: DialogDisplayer.getDefault().notify(ndm);
390: }
391: return;
392: }
393:
394: if (ex instanceof IOException) {
395: String exStr = NbBundle.getMessage(
396: RetrieverEngineImpl.class,
397: "EXCEPTION_CYCLIC_REFERENCE_INDICATOR");
398: if (ex.getMessage().startsWith(exStr)) {
399: outputMessage(ex.getMessage()
400: + ":\n\t "
401: + NbBundle.getMessage(
402: RetrieverEngineImpl.class,
403: "MSG_retrieving_location_found_in",
404: rent.getCurrentAddress(), rent
405: .getBaseAddress()));
406: return;
407: }
408: String errorMess = NbBundle.getMessage(
409: RetrieverEngineImpl.class, "MSG_general_io_error",
410: ex.getMessage());
411: if (showErrorPopup) {
412: NotifyDescriptor.Message ndm = new NotifyDescriptor.Message(
413: errorMess,
414: NotifyDescriptor.Message.ERROR_MESSAGE);
415: DialogDisplayer.getDefault().notify(ndm);
416: }
417: outputError(errorMess);
418: return;
419: }
420:
421: outputError(ex.getMessage());
422: return;
423:
424: }
425:
426: String opTabTitle = NbBundle.getMessage(RetrieverEngineImpl.class,
427: "TITLE_retriever_output_tab_title"); //NOI18N
428:
429: InputOutput iop = null;
430:
431: private InputOutput getOPWindow() {
432: if (iop == null) {
433: iop = IOProvider.getDefault().getIO(opTabTitle, false);
434: iop.setErrSeparated(true);
435: iop.setFocusTaken(false);
436: /*iop.select();
437: try {
438: iop.getOut().reset();
439: } catch (IOException ex) {
440: }*/
441: ioOut = iop.getOut();
442: DateFormat dtf = DateFormat.getDateTimeInstance();
443: ioOut.print("\n\n"
444: + dtf.format(new Date(System.currentTimeMillis()))
445: + " : ");
446: }
447: return iop;
448: }
449:
450: private void closeOPOuts() {
451: getErrOut().close();
452: getOPOut().close();
453: }
454:
455: OutputWriter ioOut;
456:
457: private OutputWriter getOPOut() {
458: if (ioOut == null) {
459: ioOut = getOPWindow().getOut();
460: }
461: return ioOut;
462: }
463:
464: OutputWriter ioError;
465:
466: private OutputWriter getErrOut() {
467: if (ioError == null) {
468: ioError = getOPWindow().getErr();
469: }
470: return ioError;
471: }
472:
473: private void outputError(String str) {
474: OutputWriter err = getErrOut();
475: err.println(NbBundle.getMessage(RetrieverEngineImpl.class,
476: "MSG_Error_str", str)); //NOI18N
477: err.flush();
478: }
479:
480: private void outputMessage(String str) {
481: OutputWriter err = getOPOut();
482: err.println(str); //NOI18N
483: err.flush();
484: }
485:
486: private void updateDownloadingInfo(RetrieveEntry rent) {
487: OutputWriter opt = getOPOut();
488: if (rent.getBaseAddress() != null) {
489: opt.println(NbBundle
490: .getMessage(RetrieverEngineImpl.class,
491: "MSG_retrieving_location_found_in", rent
492: .getCurrentAddress(), rent
493: .getBaseAddress())); //NOI18N
494: } else {
495: opt.println(NbBundle
496: .getMessage(RetrieverEngineImpl.class,
497: "MSG_retrieving_location", rent
498: .getCurrentAddress())); //NOI18N
499: }
500: opt.flush();
501: }
502:
503: List<RetrieveEntry> retrievedList = new ArrayList<RetrieveEntry>();
504:
505: public List<RetrieveEntry> getRetrievedList() {
506: return retrievedList;
507: }
508:
509: private void updateDownloadedInfo(RetrieveEntry rent) {
510: retrievedList.add(rent);
511: OutputWriter opt = getOPOut();
512: String str = " " + rent.getEffectiveAddress();
513: opt.println(NbBundle.getMessage(RetrieverEngineImpl.class,
514: "MSG_retrieved_saved_at", str, rent.getSaveFile())); //NOI18N
515: opt.flush();
516: }
517:
518: public File getSeedFileLocation() {
519: if (retrievedList.size() > 0) {
520: RetrieveEntry rent = retrievedList.get(0);
521: return rent.getSaveFile();
522: }
523: return null;
524: }
525:
526: private void createCatalogIfRequired(RetrieveEntry rent) {
527: URI curURI = null;
528: String addr = rent.getEffectiveAddress();
529: try {
530: //check if this is the first entry and the connection was redirected. If yes, then
531: //store the URI as the original URI instead of the redirected URI
532: String tempStr = URLResourceRetriever.resolveURL(rent
533: .getBaseAddress(), rent.getCurrentAddress());
534: if (!(new URI(tempStr).equals(new URI(addr)))) {
535: addr = tempStr;
536: }
537: } catch (URISyntaxException ex) {
538: //ignore
539: }
540: if (isSave2SingleFolder()) {
541: if (!rent.getCurrentAddress().equals(
542: rent.getEffectiveAddress()))
543: addr = rent.getCurrentAddress();
544: }
545: try {
546: curURI = new URI(addr);
547: } catch (URISyntaxException ex) {
548: //this is not supposed to happen. But if it does, then just return
549: return;
550: }
551: FileObject fobj = null;
552: try {
553: fobj = FileUtil.toFileObject(FileUtil.normalizeFile(rent
554: .getSaveFile()));
555: } catch (Exception e) {
556: return;
557: }
558: if (fobj == null)
559: return;
560: CatalogWriteModel dr = null;
561: try {
562: if (this .catalogFileObject == null)
563: dr = CatalogWriteModelFactory.getInstance()
564: .getCatalogWriteModelForProject(fobj);
565: else
566: dr = CatalogWriteModelFactory.getInstance()
567: .getCatalogWriteModelForCatalogFile(
568: this .catalogFileObject);
569: } catch (CatalogModelException ex) {
570: //ignore this exception but return
571: return;
572: }
573: //fobj = FileUtil.toFileObject(rent.getSaveFile());
574: try {
575: dr.addURI(curURI, fobj);
576: } catch (Exception ex) {
577: //ignore this exception but return
578: ex = new Exception(
579: "Exception while writing in to catalog.", ex);
580: handleException(rent, ex);
581: return;
582: }
583: }
584:
585: boolean fileOverwrite = false;
586:
587: public void setFileOverwrite(boolean fileOverwrite) {
588: this .fileOverwrite = fileOverwrite;
589: }
590:
591: public boolean getFileOverwrite() {
592: return fileOverwrite;
593: }
594:
595: Map<RetrieveEntry, Exception> audits;
596:
597: public Map<RetrieveEntry, Exception> getRetrievedResourceExceptionMap() {
598: return audits;
599: }
600:
601: FileObject catalogFileObject = null;
602:
603: public void setCatalogFile(FileObject catalogFileObject) {
604: this .catalogFileObject = catalogFileObject;
605: }
606:
607: private boolean save2SingleFolder = false;
608:
609: public void setSave2SingleFolder(boolean save2SingleFolder) {
610: this .save2SingleFolder = save2SingleFolder;
611: }
612:
613: public boolean isSave2SingleFolder() {
614: return save2SingleFolder;
615: }
616: }
|