001: /*
002: * Copyright 2004 Outerthought bvba and Schaubroeck nv
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.outerj.daisy.tools.importexport.import_;
017:
018: import org.outerj.daisy.tools.importexport.import_.namespaces.NamespaceImporter;
019: import org.outerj.daisy.tools.importexport.import_.fs.ImportFile;
020: import org.outerj.daisy.tools.importexport.import_.fs.ImportFileEntry;
021: import org.outerj.daisy.tools.importexport.import_.schema.SchemaImporter;
022: import org.outerj.daisy.tools.importexport.import_.documents.DocumentLoaderFactory;
023: import org.outerj.daisy.tools.importexport.import_.documents.DocumentLoader;
024: import org.outerj.daisy.tools.importexport.import_.documents.DocumentImportResult;
025: import org.outerj.daisy.tools.importexport.import_.config.ImportOptions;
026: import org.outerj.daisy.tools.importexport.import_.variants.VariantImporter;
027: import org.outerj.daisy.tools.importexport.import_.retireddocs.RetiredDocumentsImporter;
028: import org.outerj.daisy.tools.importexport.import_.collections.CollectionImporter;
029: import org.outerj.daisy.tools.importexport.model.ImpExpVariantKey;
030: import org.outerj.daisy.tools.importexport.model.meta.ImpExpMeta;
031: import org.outerj.daisy.tools.importexport.model.meta.ImpExpMetaDexmlizer;
032: import org.outerj.daisy.tools.importexport.ImportExportException;
033: import org.outerj.daisy.tools.importexport.docset.DocumentSet;
034: import org.outerj.daisy.tools.importexport.docset.DocumentSetHelper;
035: import org.outerj.daisy.repository.Repository;
036: import org.outerj.daisy.repository.AccessException;
037: import org.outerj.daisy.repository.DocumentLockedException;
038:
039: import java.util.regex.Matcher;
040: import java.util.regex.Pattern;
041: import java.util.regex.PatternSyntaxException;
042: import java.util.List;
043: import java.util.ArrayList;
044: import java.util.Set;
045: import java.io.InputStream;
046:
047: /**
048: * This is the core of the import tool, use this class to programatically
049: * perform an export.
050: */
051: public class Importer {
052: private ImportFile importFile;
053: private DocumentSet documentSet;
054: private Set importSubSet;
055: private ImportListener listener;
056: private Repository repository;
057: private ImportOptions options;
058: private ImpExpMeta meta;
059:
060: private static Pattern VARIANT_DIR_NAME_PATTERN = Pattern
061: .compile("^([^~]+)~([^~]+)$");
062:
063: /**
064: * Entry point for doing an import.
065: */
066: public static void run(ImportFile importFile,
067: Repository repository, ImportOptions options,
068: ImportListener listener) throws Exception {
069: run(importFile, null, repository, options, listener);
070: }
071:
072: /**
073: * Entry point for doing an import.
074: *
075: * @param documentSet specifies a subset of documents to be imported
076: */
077: public static void run(ImportFile importFile,
078: DocumentSet documentSet, Repository repository,
079: ImportOptions options, ImportListener listener)
080: throws Exception {
081: if (importFile == null)
082: throw new IllegalArgumentException(
083: "Null argument: importFile");
084: if (repository == null)
085: throw new IllegalArgumentException(
086: "Null argument: repository");
087: if (options == null)
088: throw new IllegalArgumentException("Null argument: options");
089: if (listener == null)
090: throw new IllegalArgumentException(
091: "Null argument: listener");
092:
093: new Importer(importFile, documentSet, repository, options,
094: listener).run();
095: }
096:
097: private Importer(ImportFile importFile, DocumentSet documentSet,
098: Repository repository, ImportOptions options,
099: ImportListener listener) {
100: this .importFile = importFile;
101: this .documentSet = documentSet;
102: this .listener = listener;
103: this .repository = repository;
104: this .options = options;
105: }
106:
107: private void run() throws Exception {
108: readMeta(importFile);
109: checkInterrupted();
110:
111: NamespaceImporter.run(importFile, listener, repository);
112: checkInterrupted();
113:
114: CollectionImporter.run(importFile, listener, repository);
115: checkInterrupted();
116:
117: VariantImporter.run(importFile, listener, repository);
118: checkInterrupted();
119:
120: SchemaImporter.run(importFile, options, listener, repository);
121: checkInterrupted();
122:
123: determineDocumentSubSet();
124: checkInterrupted();
125:
126: importDocuments();
127: checkInterrupted();
128:
129: importRetiredDocuments();
130: }
131:
132: private void determineDocumentSubSet() throws Exception {
133: // Determine subset of docs to import, if any
134: if (documentSet != null) {
135: try {
136: importSubSet = DocumentSetHelper.toImpExpVariantKeys(
137: documentSet.getDocuments(), repository);
138: documentSet = null;
139: } catch (Exception e) {
140: throw new ImportExportException(
141: "Error getting subset of documents to imports.",
142: e);
143: }
144: }
145: }
146:
147: private void importDocuments() throws Exception {
148: listener.startActivity("Importing documents.");
149:
150: if (!importFile.exists("documents")) {
151: listener
152: .info("Import does not contain a document directory, will skip document import.");
153: return;
154: }
155:
156: DocumentLoader documentLoader = null;
157: if (options.getCheckVersion()) {
158: String exportDaisyServerVersion = meta
159: .getDaisyServerVersion();
160: if (exportDaisyServerVersion != null) {
161: documentLoader = DocumentLoaderFactory
162: .getDocumentLoader(exportDaisyServerVersion);
163: }
164: }
165: if (documentLoader == null)
166: documentLoader = DocumentLoaderFactory.getDocumentLoader();
167:
168: // First search for all documents to import
169: listener.info("Determing list of documents to import.");
170: List<DocumentToImport> documentsToImport = new ArrayList<DocumentToImport>();
171: ImportFileEntry[] docEntries = importFile.getPath("documents")
172: .getChildren();
173:
174: Pattern excludePattern;
175: try {
176: excludePattern = Pattern.compile(options
177: .getExcludeFilesPattern());
178: } catch (PatternSyntaxException e) {
179: throw new ImportExportException(
180: "Error in exclude file pattern: "
181: + options.getExcludeFilesPattern(), e);
182: }
183:
184: for (ImportFileEntry entry : docEntries) {
185: String documentId = entry.getName();
186:
187: Matcher docExcludeMatcher = excludePattern.matcher(entry
188: .getName());
189: if (docExcludeMatcher.matches())
190: continue;
191:
192: ImportFileEntry[] variantEntries = entry.getChildren();
193: for (ImportFileEntry variantEntry : variantEntries) {
194: checkInterrupted();
195: Matcher variantExcludeMatcher = excludePattern
196: .matcher(variantEntry.getName());
197: Matcher matcher = VARIANT_DIR_NAME_PATTERN
198: .matcher(variantEntry.getName());
199: if (!variantEntry.isDirectory()) {
200: // a normal file: silently skip it
201: } else if (variantExcludeMatcher.matches()) {
202: // matches file exclusion pattern, silently skip it
203: } else if (matcher.matches()) {
204: String branch = matcher.group(1);
205: String language = matcher.group(2);
206: ImpExpVariantKey key = new ImpExpVariantKey(
207: documentId, branch, language);
208: if (importSubSet == null
209: || importSubSet.contains(key))
210: documentsToImport.add(new DocumentToImport(
211: documentId, branch, language,
212: variantEntry));
213: } else {
214: listener
215: .info("Encountered a directory that does not match the naming convention (will skip it): "
216: + variantEntry.getPath());
217: }
218: }
219: }
220:
221: // Start the actual import
222: listener.info("There are " + documentsToImport.size()
223: + " document/s to import.");
224: listener.startDocumentProgress(documentsToImport.size());
225: try {
226: for (int i = 0; i < documentsToImport.size(); i++) {
227: checkInterrupted();
228: listener.updateDocumentProgress(i);
229: DocumentToImport doc = documentsToImport.get(i);
230: importDocument(doc, documentLoader);
231: }
232: } finally {
233: listener.endDocumentProgress();
234: }
235: }
236:
237: private void importDocument(DocumentToImport doc,
238: DocumentLoader documentLoader) throws Exception {
239: String documentId = doc.getDocumentId();
240: String branch = doc.getBranch();
241: String language = doc.getLanguage();
242: ImpExpVariantKey variantKey = new ImpExpVariantKey(documentId,
243: branch, language);
244:
245: DocumentImportResult result = null;
246: boolean gotError = false;
247: try {
248: result = documentLoader.run(documentId, branch, language,
249: doc.getEntry(), repository, options, listener);
250: } catch (Throwable throwable) {
251: gotError = true;
252: if (throwable instanceof AccessException) {
253: listener.permissionDenied(variantKey,
254: (AccessException) throwable);
255: } else if (throwable instanceof DocumentLockedException) {
256: listener.lockedDocument(variantKey,
257: (DocumentLockedException) throwable);
258: } else {
259: listener.failed(variantKey, throwable);
260: }
261: }
262:
263: if (!gotError) {
264: listener.success(variantKey, result);
265: }
266: }
267:
268: private void importRetiredDocuments() throws Exception {
269: listener.startActivity("Importing retired documents");
270:
271: if (importFile.exists("info/retired.xml")) {
272: RetiredDocumentsImporter.run(importFile, importSubSet,
273: listener, repository);
274: } else {
275: listener.info("No info/retired.xml found.");
276: }
277: }
278:
279: static class DocumentToImport {
280: String documentId;
281: String branch;
282: String language;
283: ImportFileEntry entry;
284:
285: public DocumentToImport(String documentId, String branch,
286: String language, ImportFileEntry entry) {
287: this .documentId = documentId;
288: this .branch = branch;
289: this .language = language;
290: this .entry = entry;
291: }
292:
293: public String getDocumentId() {
294: return documentId;
295: }
296:
297: public String getBranch() {
298: return branch;
299: }
300:
301: public String getLanguage() {
302: return language;
303: }
304:
305: public ImportFileEntry getEntry() {
306: return entry;
307: }
308: }
309:
310: private void readMeta(ImportFile importFile) throws Exception {
311: String META_FILE_PATH = "info/meta.xml";
312:
313: if (!importFile.exists(META_FILE_PATH)) {
314: listener.info("No " + META_FILE_PATH + " found.");
315: this .meta = new ImpExpMeta();
316: return;
317: }
318:
319: InputStream is = null;
320: try {
321: is = importFile.getPath(META_FILE_PATH).getInputStream();
322: this .meta = ImpExpMetaDexmlizer.fromXml(is);
323: } finally {
324: if (is != null)
325: is.close();
326: }
327: }
328:
329: private void checkInterrupted() throws ImportExportException {
330: if (listener.isInterrupted()) {
331: throw new ImportExportException(
332: "Import was interrupted on user's request.");
333: }
334: }
335: }
|