View Javadoc

1   /*
2    * This file is a part of CAST project.
3    * (c) Copyright 2007, AGH University of Science & Technology
4    * https://caribou.iisg.agh.edu.pl/trac/cast
5    *
6    * Licensed under the Eclipse Public License, Version 1.0 (the "License").
7    * You may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    * http://www.eclipse.org/legal/epl-v10.html
10   */
11  /*
12   * File: XStreamInitializer.java
13   * Created: 2007-00-00
14   * Author: kpietak, awos
15   * $Id: XStreamInitializer.java 3020 2009-07-17 14:41:19Z kpietak $
16   */
17  
18  package pl.edu.agh.cast.backward.resources.xml;
19  
20  import java.lang.reflect.Field;
21  import java.util.Arrays;
22  import java.util.Comparator;
23  import java.util.Map;
24  
25  import pl.edu.agh.cast.Activator;
26  import pl.edu.agh.cast.model.attributes.Attribute;
27  import pl.edu.agh.cast.model.attributes.AttributeManager;
28  import pl.edu.agh.cast.model.attributes.AttributeMergePolicy;
29  import pl.edu.agh.cast.model.attributes.AttributeValue;
30  import pl.edu.agh.cast.model.visual.backward.Connection;
31  import pl.edu.agh.cast.model.visual.backward.Diagram;
32  import pl.edu.agh.cast.model.visual.backward.DiagramSettings;
33  import pl.edu.agh.cast.model.visual.backward.IDiagramSettings;
34  import pl.edu.agh.cast.model.visual.backward.ModelElement;
35  import pl.edu.agh.cast.model.visual.backward.Node;
36  import pl.edu.agh.cast.model.visual.backward.VisualModelCachingFactory;
37  
38  import com.thoughtworks.xstream.XStream;
39  import com.thoughtworks.xstream.converters.reflection.FieldDictionary;
40  import com.thoughtworks.xstream.converters.reflection.FieldKey;
41  import com.thoughtworks.xstream.converters.reflection.FieldKeySorter;
42  import com.thoughtworks.xstream.converters.reflection.Sun14ReflectionProvider;
43  import com.thoughtworks.xstream.core.util.OrderRetainingMap;
44  
45  /**
46   * Helper class which is responsible for providing and initialization of XStream object.
47   *
48   * @author AGH CAST Team
49   */
50  public class XStreamInitializer {
51  
52  	/**
53  	 * A custom XStream {@link FieldKeySorter} that puts all attribute managers to the beginning. This prevents problems
54  	 * with marshaling attribute values before attributes were marshaled.
55  	 *
56  	 * @author AGH CAST Team
57  	 */
58  	private static final class AttributeManagersFirstKeySorter implements FieldKeySorter {
59  
60  		/**
61  		 * Compares field key names so that those with ATTRIBUTE_MANAGER_FIELD_NAME_SUBSTRING are first.
62  		 *
63  		 * @author AGH CAST Team
64  		 */
65  		private static final class FieldKeyComparator implements Comparator<FieldKey> {
66  			public int compare(FieldKey o1, FieldKey o2) {
67  				if (isAttributeManagerField(o1)) {
68  					return -1;
69  				} else if (isAttributeManagerField(o2)) {
70  					return 1;
71  				} else {
72  					return 0;
73  				}
74  			}
75  
76  			private boolean isAttributeManagerField(FieldKey fieldKey) {
77  				try {
78  					Field field = fieldKey.getDeclaringClass().getDeclaredField(fieldKey.getFieldName());
79  					return AttributeManager.class.isAssignableFrom(field.getType());
80  				} catch (Exception e) {
81  					// this should not happen, but anyway...
82  					Activator.getLogger().warn("Exception when sorting fields", e); //$NON-NLS-1$
83  					return false;
84  				}
85  			}
86  		}
87  
88  		@SuppressWarnings("unchecked")
89  		public Map sort(Class type, Map keyedByFieldKey) {
90  
91  			if (Diagram.class.isAssignableFrom(type)) {
92  				/**
93  				 * Move all AttributeManager type fields at the beginning of the map
94  				 */
95  				FieldKey[] fieldKeys = (FieldKey[])keyedByFieldKey.keySet().toArray(
96  				        new FieldKey[keyedByFieldKey.size()]);
97  				Arrays.sort(fieldKeys, new FieldKeyComparator());
98  
99  				Map result = new OrderRetainingMap();
100 				for (int i = 0; i < fieldKeys.length; i++) {
101 					result.put(fieldKeys[i], keyedByFieldKey.get(fieldKeys[i]));
102 				}
103 				return result;
104 			} else {
105 				// only change field order for descendants of Diagram
106 				return keyedByFieldKey;
107 			}
108 		}
109 	}
110 
111 	private static final Class<?>[] CLASSES_WITH_ALIASES = { XMLProjectContainer.class, Diagram.class,
112 		DiagramSettings.class, ModelElement.class, VisualModelCachingFactory.class, Connection.class, Node.class,
113 	   	AttributeValue.class, Attribute.class, AttributeMergePolicy.MergePolicyAlwaysFirst.class,
114 	   	AttributeMergePolicy.MergePolicyAlwaysSecond.class, AttributeMergePolicy.MergePolicyLogicalAnd.class,
115 	   	AttributeMergePolicy.MergePolicyLogicalOr.class };
116 
117 	/**
118 	 * Creates and initializes a new XStream instance with default set of classes.
119 	 *
120 	 * @return a new instance of XStream
121 	 */
122 	public static XStream createXStreamInstance() {
123 		return init(null);
124 	}
125 
126 	/**
127 	 * Creates and initializes a new XStream instance.
128 	 *
129 	 * @param classes
130 	 *            which contains annotations for XStream
131 	 * @return a new instance of XStream
132 	 */
133 	public static XStream createXStreamInstance(Class<?>[] classes) {
134 		return init(classes);
135 	}
136 
137 	private static XStream init(Class<?>[] additionalClassesWithAliases) {
138 		XStream xstream = new XStream(new Sun14ReflectionProvider(new FieldDictionary(
139 		        new AttributeManagersFirstKeySorter())));
140 
141 		// read aliases
142 		xstream.processAnnotations(CLASSES_WITH_ALIASES);
143 		if (additionalClassesWithAliases != null) {
144 			xstream.processAnnotations(additionalClassesWithAliases);
145 		}
146 		// autodetect annotations in classes extending default visual model
147 		// classes
148 		xstream.autodetectAnnotations(true);
149 
150 		// add default implementations to avoid
151 		// class attribute in xml tag
152 		xstream.addDefaultImplementation(DiagramSettings.class, IDiagramSettings.class);
153 
154 		// add custom converters
155 		xstream.registerConverter(new VisualModelCachingFactoryConverter());
156 		xstream.registerConverter(new AttributeManagerConverter());
157 		xstream.registerConverter(new AttributeValuesConverter());
158 
159 		return xstream;
160 	}
161 
162 }