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: package org.netbeans.modules.vmd.io;
042:
043: import org.netbeans.modules.vmd.api.io.serialization.DocumentErrorHandlerSupport;
044: import org.netbeans.modules.vmd.api.io.DataObjectContext;
045: import org.netbeans.modules.vmd.api.io.DataSerializer;
046: import org.netbeans.modules.vmd.api.io.providers.IOSupport;
047: import org.netbeans.modules.vmd.api.io.serialization.ComponentElement;
048: import org.netbeans.modules.vmd.api.io.serialization.PropertyElement;
049: import org.netbeans.modules.vmd.api.io.serialization.DocumentSerializationController;
050: import org.netbeans.modules.vmd.api.model.*;
051: import org.openide.filesystems.FileLock;
052: import org.openide.filesystems.FileObject;
053: import org.openide.filesystems.FileSystem;
054: import org.openide.xml.XMLUtil;
055: import org.openide.util.Lookup;
056: import org.w3c.dom.*;
057: import org.xml.sax.ErrorHandler;
058: import org.xml.sax.InputSource;
059: import org.xml.sax.SAXException;
060: import org.xml.sax.SAXParseException;
061: import java.io.IOException;
062: import java.io.InputStream;
063: import java.util.*;
064: import org.netbeans.modules.vmd.api.io.serialization.DocumentErrorHandler;
065: import org.openide.util.NbBundle;
066:
067: /**
068: * @author David Kaspar
069: */
070: // TODO - check for design and document version
071: public class DocumentLoad {
072:
073: private static final String XML_ERROR = NbBundle.getMessage(
074: DocumentLoad.class, "MSG_BrokenXML_Error"); //NOI18N
075: private static final String WRONG_VERSION_ERROR = NbBundle
076: .getMessage(DocumentLoad.class,
077: "MSG_Wrong_VMD_Version_Error"); //NOI18N
078: private static final String DESERIALIZATION_ERROR = NbBundle
079: .getMessage(DocumentLoad.class, "MSG_Deserialization_Error"); //NOI18N
080: private static final String DESCRIPTOR_MISSING_ERROR = NbBundle
081: .getMessage(DocumentLoad.class,
082: "MSG_MissingDescriptor_Error"); //NOI18N
083:
084: private static Collection<? extends DocumentSerializationController> getDocumentSerializationControllers() {
085: return Lookup.getDefault().lookupAll(
086: DocumentSerializationController.class);
087: }
088:
089: public static boolean load(DataObjectContext context,
090: DesignDocument loadingDocument,
091: DocumentErrorHandler errorHandler) {
092: final Node rootNode;
093: try {
094: rootNode = getRootNode(IOSupport.getDesignFile(context));
095: } catch (IOException e) {
096: throw Debug.error(e);
097: }
098:
099: if (!DocumentSave.VERSION_VALUE_1.equals(getAttributeValue(
100: rootNode, DocumentSave.VERSION_ATTR))) {
101: Debug.warning("Invalid version of VisualDesign"); // NOI18N
102: errorHandler.addWarning(WRONG_VERSION_ERROR);
103: return false;
104: }
105:
106: return loadVersion1(context, loadingDocument, rootNode,
107: errorHandler);
108: }
109:
110: private static boolean loadVersion1(DataObjectContext context,
111: DesignDocument loadingDocument, Node rootNode,
112: DocumentErrorHandler errorHandler) {
113: final Node documentNode = findDocumentNode(rootNode);
114:
115: loadDocumentVersion1(context, loadingDocument, documentNode,
116: errorHandler);
117: if (!errorHandler.getErrors().isEmpty()) {
118: return false;
119: }
120: Collection<? extends DataSerializer> serializers = DocumentSave.customDataSerializers
121: .allInstances();
122: for (Node node : getChildNode(rootNode)) {
123: if (isDocumentNode(node)) {
124: continue;
125: }
126: for (DataSerializer serializer : serializers) {
127: if (serializer.deserializeData(context,
128: loadingDocument, node)) {
129: break;
130: }
131: }
132: }
133: return true;
134: }
135:
136: private static void loadDocumentVersion1(
137: final DataObjectContext context,
138: final DesignDocument loadingDocument, Node documentNode,
139: final DocumentErrorHandler errorHandler) {
140: final String documentVersion = getAttributeValue(documentNode,
141: DocumentSave.VERSION_ATTR);
142:
143: ArrayList<ComponentElement> componentElements = new ArrayList<ComponentElement>();
144: if (documentNode != null) {
145: for (Node child : getChildNode(documentNode)) {
146: if (isComponentNode(child)) {
147: collectStructure(componentElements, child,
148: Long.MIN_VALUE, errorHandler);
149: }
150: }
151: }
152: for (DocumentSerializationController controller : getDocumentSerializationControllers()) {
153: controller.approveComponents(context, loadingDocument,
154: documentVersion, componentElements, errorHandler);
155: if (!errorHandler.getErrors().isEmpty()) {
156: return;
157: }
158: }
159: final HashMap<Long, ComponentElement> hierarchy = new HashMap<Long, ComponentElement>();
160: HashSet<TypeID> typeids = new HashSet<TypeID>();
161: for (ComponentElement element : componentElements) {
162: hierarchy.put(element.getUID(), element);
163: typeids.add(element.getTypeID());
164: }
165:
166: // loadingDocument.getDescriptorRegistry().assertComponentDescriptors(typeids);
167:
168: loadingDocument.getTransactionManager().writeAccess(
169: new Runnable() {
170:
171: public void run() {
172: loadDocumentCore(context, loadingDocument,
173: documentVersion, hierarchy,
174: errorHandler);
175: for (DocumentSerializationController controller : getDocumentSerializationControllers()) {
176: controller.postValidateDocument(context,
177: loadingDocument, documentVersion,
178: errorHandler);
179: if (!errorHandler.getErrors().isEmpty()) {
180: return;
181: }
182: }
183: }
184: });
185: }
186:
187: private static void loadDocumentCore(DataObjectContext context,
188: DesignDocument loadingDocument, String documentVersion,
189: HashMap<Long, ComponentElement> hierarchy,
190: DocumentErrorHandler errorHandler) {
191: ArrayList<ComponentElement> list = new ArrayList<ComponentElement>(
192: hierarchy.values());
193: Collections.sort(list, new Comparator<ComponentElement>() {
194:
195: public int compare(ComponentElement o1, ComponentElement o2) {
196: return (int) (o1.getUID() - o2.getUID());
197: }
198: });
199:
200: for (ComponentElement element : list) {
201: long componentid = element.getUID();
202: loadingDocument.setPreferredComponentID(componentid);
203: if (loadingDocument.getDescriptorRegistry()
204: .getComponentDescriptor(element.getTypeID()) == null) {
205: if (element.getUID() == 0) {
206: Debug.warning(
207: "Missing ComponentDescriptor in registry ",
208: element.getTypeID()); // NOI18N
209: errorHandler.addError("{0} {1}",
210: DESCRIPTOR_MISSING_ERROR, element
211: .getTypeID().toString()); //NOI18N
212: continue;
213: } else {
214: Debug.warning(
215: "Missing ComponentDescriptor in registry ",
216: element.getTypeID()); // NOI18N
217: errorHandler.addWarning("{0} {1}",
218: DESCRIPTOR_MISSING_ERROR, element
219: .getTypeID().toString()); //NOI18N
220: continue;
221: }
222: }
223: if (!errorHandler.getErrors().isEmpty()) {
224: return;
225: }
226: DesignComponent component = loadingDocument
227: .createRawComponent(element.getTypeID());
228: assert component.getComponentID() == componentid;
229: assert component.getComponentDescriptor() != null;
230: }
231:
232: for (ComponentElement element : hierarchy.values()) {
233: long parentuid = element.getParentUID();
234: DesignComponent parent = loadingDocument
235: .getComponentByUID(parentuid);
236: DesignComponent component = loadingDocument
237: .getComponentByUID(element.getUID());
238: if (component == null) {
239: continue;
240: }
241: if (parentuid != Long.MIN_VALUE) {
242: if (parent == null) {
243: continue;
244: }
245: parent.addComponent(component);
246: }
247: }
248:
249: for (ComponentElement element : hierarchy.values()) {
250: DesignComponent component = loadingDocument
251: .getComponentByUID(element.getUID());
252: if (component == null) {
253: continue;
254: }
255: ComponentDescriptor descriptor = component
256: .getComponentDescriptor();
257: if (descriptor == null) {
258: continue;
259: }
260: Node[] propertyNodes = getChildNode(element.getNode());
261: ArrayList<PropertyElement> propertyElements = new ArrayList<PropertyElement>();
262: for (Node propertyNode : propertyNodes) {
263: if (!isPropertyNode(propertyNode)) {
264: continue;
265: }
266: String propertyName = getAttributeValue(propertyNode,
267: DocumentSave.NAME_ATTR);
268: TypeID typeid = TypeID.createFrom(getAttributeValue(
269: propertyNode, DocumentSave.TYPEID_ATTR));
270: String serialized = getAttributeValue(propertyNode,
271: DocumentSave.VALUE_ATTR);
272: propertyElements.add(PropertyElement.create(
273: propertyName, typeid, serialized));
274: }
275:
276: for (DocumentSerializationController controller : getDocumentSerializationControllers()) {
277: controller.approveProperties(context, loadingDocument,
278: documentVersion, component, propertyElements,
279: errorHandler);
280: }
281: for (PropertyElement propertyElement : propertyElements) {
282: String propertyName = propertyElement.getPropertyName();
283: if (propertyName == null
284: || descriptor
285: .getPropertyDescriptor(propertyName) == null) {
286: Debug.warning("Missing property descriptor",
287: component, propertyName); // NOI18N
288: errorHandler.addWarning("{0} {1} - {2}", NbBundle
289: .getMessage(DocumentLoad.class,
290: "MSG_MissingProperty_Error"),
291: component, propertyName); // NOI18N
292: continue;
293: }
294: PropertyValue value;
295: try {
296: value = PropertyValue.deserialize(propertyElement
297: .getSerialized(), loadingDocument,
298: propertyElement.getTypeID());
299: } catch (Exception e) {
300: Debug.warning(
301: "Error while deserializing property value",
302: component, propertyName); // NOI18N
303: errorHandler.addWarning("{0} {1} {2} {3}",
304: DESERIALIZATION_ERROR, component,
305: propertyName, propertyElement
306: .getSerialized()); //NOI18N
307: value = PropertyValue.createNull();
308: }
309: component.writeProperty(propertyName, value);
310: }
311: }
312:
313: DesignComponent componentByUID = loadingDocument
314: .getComponentByUID(0);
315: if (componentByUID != null) {
316: loadingDocument.setRootComponent(componentByUID);
317: }
318: }
319:
320: private static void collectStructure(
321: Collection<ComponentElement> componentElements, Node node,
322: long parent, DocumentErrorHandler errorHandler) {
323: String id = getAttributeValue(node,
324: DocumentSave.COMPONENTID_ATTR);
325: if (id == null) {
326: StringBuffer sb = new StringBuffer();
327: for (int i = 0; i < node.getAttributes().getLength(); i++) {
328: sb.append(" "); //NOI18N
329: sb.append(node.getAttributes().item(i));
330: }
331: errorHandler.addError(NbBundle.getMessage(
332: DocumentLoad.class, "MSG_Wrong_argument")
333: + sb.toString()); //NOI18N
334: return;
335: }
336: long componentid = -1;
337: try {
338: componentid = Long.parseLong(id);
339: } catch (NumberFormatException ex) {
340: errorHandler
341: .addError("{0} {1}", NbBundle.getMessage(
342: DocumentLoad.class,
343: "MSG_Wrong_argument_value"), id); //NOI18N
344: return;
345: }
346: TypeID typeid = TypeID.createFrom(getAttributeValue(node,
347: DocumentSave.TYPEID_ATTR));
348: componentElements.add(ComponentElement.create(parent,
349: componentid, typeid, node));
350:
351: Node[] children = getChildNode(node);
352: for (Node child : children) {
353: if (isComponentNode(child)) {
354: collectStructure(componentElements, child, componentid,
355: errorHandler);
356: }
357: }
358: }
359:
360: private static boolean isDocumentNode(Node child) {
361: return DocumentSave.DOCUMENT_NODE.equals(child.getNodeName());
362: }
363:
364: private static boolean isComponentNode(Node child) {
365: return DocumentSave.COMPONENT_NODE.equals(child.getNodeName());
366: }
367:
368: private static boolean isPropertyNode(Node child) {
369: return DocumentSave.PROPERTY_NODE.equals(child.getNodeName());
370: }
371:
372: private static Node[] getChildNode(Node node) {
373: NodeList childNodes = node.getChildNodes();
374: Node[] nodes = new Node[childNodes != null ? childNodes
375: .getLength() : 0];
376: for (int i = 0; i < nodes.length; i++) {
377: nodes[i] = childNodes.item(i);
378: }
379: return nodes;
380: }
381:
382: private static Node findDocumentNode(Node rootNode) {
383: for (Node node : getChildNode(rootNode)) {
384: if (isDocumentNode(node)) {
385: return node;
386: }
387: }
388: return null;
389: }
390:
391: // static void createEmpty (DataObjectContext context, DesignDocument loadingDocument) {
392: // final TypeID type = ProjectTypeInfo.getProjectTypeInfoFor (context.getProjectType ()).getRootCDTypeID ();
393: // final DescriptorRegistry descriptorRegistry = loadingDocument.getDescriptorRegistry ();
394: // final boolean[] ret = new boolean[1];
395: // descriptorRegistry.readAccess (new Runnable() {
396: // public void run () {
397: // ret[0] = descriptorRegistry.getComponentDescriptor (type) != null;
398: // }
399: // });
400: // if (ret[0]) {
401: // DesignComponent root = loadingDocument.createComponent (type);
402: // loadingDocument.setRootComponent (root);
403: // }
404: // }
405:
406: private static Node getRootNode(final FileObject fileObject)
407: throws IOException {
408: synchronized (DocumentSave.sync) {
409: final Node[] node = new Node[1];
410: fileObject.getFileSystem().runAtomicAction(
411: new FileSystem.AtomicAction() {
412:
413: public void run() throws IOException {
414: Document document = null;
415: if (fileObject != null) {
416: FileLock lock = null;
417: try {
418: lock = fileObject.lock();
419: document = getXMLDocument(fileObject);
420: } finally {
421: if (lock != null) {
422: lock.releaseLock();
423: }
424: }
425: }
426: node[0] = document != null ? document
427: .getFirstChild() : null;
428: }
429: });
430: return node[0];
431: }
432: }
433:
434: private static Document getXMLDocument(FileObject fileObject)
435: throws IOException {
436: Document doc = null;
437: final InputStream is = fileObject.getInputStream();
438: final DocumentErrorHandler errorHandler = new DocumentErrorHandler();
439: try {
440: doc = XMLUtil.parse(new InputSource(is), false, false,
441: new ErrorHandler() {
442:
443: public void error(SAXParseException e)
444: throws SAXException {
445: errorHandler.addError(XML_ERROR
446: + e.getMessage());
447: }
448:
449: public void fatalError(SAXParseException e)
450: throws SAXException {
451: errorHandler.addError(XML_ERROR
452: + e.getMessage());
453: }
454:
455: public void warning(SAXParseException e) {
456: errorHandler.addWarning(XML_ERROR
457: + e.getMessage());
458: }
459: }, null);
460: } catch (SAXException e) {
461: errorHandler.addError(XML_ERROR + e.getMessage());
462: } finally {
463: try {
464: is.close();
465: } catch (IOException e) {
466: errorHandler.addError(XML_ERROR + e.getMessage());
467: }
468: }
469: DocumentErrorHandlerSupport.showDocumentErrorHandlerDialog(
470: errorHandler, fileObject);
471: return doc;
472: }
473:
474: private static String getAttributeValue(Node node, String attr) {
475: try {
476: if (node != null) {
477: NamedNodeMap map = node.getAttributes();
478: if (map != null) {
479: node = map.getNamedItem(attr);
480: if (node != null) {
481: return node.getNodeValue();
482: }
483: }
484: }
485: } catch (DOMException e) {
486: Debug.warning(e);
487: }
488: return null;
489: }
490:
491: public static String loadProjectType(DataObjectContext context) {
492: final Node rootNode;
493: try {
494: rootNode = getRootNode(IOSupport.getDesignFile(context));
495: } catch (IOException e) {
496: throw Debug.error(e);
497: }
498: return getAttributeValue(rootNode,
499: DocumentSave.PROP_PROJECT_TYPE);
500: }
501: }
|