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: Mapper.java
13   * Created: 2007-09-20
14   * Author: apohllo, entrop
15   * $Id: Mapper.java 2232 2009-01-04 22:59:53Z apohllo $
16   */
17  
18  package pl.edu.agh.cast.model.mapper;
19  
20  import java.io.File;
21  import java.sql.Connection;
22  import java.sql.DriverManager;
23  import java.sql.SQLException;
24  import java.util.Collections;
25  import java.util.HashMap;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.SortedMap;
29  
30  import org.apache.log4j.Logger;
31  import org.eclipse.core.resources.IProject;
32  import org.eclipse.core.runtime.CoreException;
33  
34  import pl.edu.agh.cast.model.base.BasePlugin;
35  import pl.edu.agh.cast.model.mapper.internal.DBLoader;
36  import pl.edu.agh.cast.model.mapper.internal.DBSaver;
37  import pl.edu.agh.cast.model.mapper.internal.XMLLoader;
38  import pl.edu.agh.cast.model.mapper.internal.XMLRemover;
39  import pl.edu.agh.cast.model.mapper.internal.XMLSaver;
40  
41  /**
42   * <p>
43   * Mapper is a gate between model and persistence system. It provides mechanisms for saving and loading model objects
44   * without any direct DB interactions.
45   * </p>
46   * <p>
47   * The idea of mapper is build on the presumption that any part of the model may be represented as a network of linked
48   * nodes. So
49   *
50   * @see pl.edu.agh.cast.model.base.metamodel.Node and
51   * @see pl.edu.agh.cast.model.base.metamodel.Link are primitives of the metamodel. Any model element is mapped to
52   *      network of nodes. This is done through annotation mechanism
53   * @see pl.edu.agh.cast.metamodel.annotation.Mapping.
54   *      </p>
55   *
56   * @author AGH CAST Team
57   *
58   */
59  public final class Mapper {
60  
61  	private static Logger log = BasePlugin.getLogger();
62  
63  	private final String[] mysqlProps = new String[] { "com.mysql.jdbc.Driver", //$NON-NLS-1$
64  	        "jdbc:mysql://localhost/cast_test", //$NON-NLS-1$
65  	        "root", //$NON-NLS-1$
66  	        "" }; //$NON-NLS-1$
67  
68  	// TODO proper implementation of singleton pattern
69  	private static Mapper instance = new Mapper();
70  
71  	private Connection conn;
72  
73  	private Map<Node, Mappable> objectCache = Collections.synchronizedMap(new HashMap<Node, Mappable>());
74  
75  	private boolean dbPresent = false;
76  
77  	private boolean useDb = false;
78  
79  	/**
80  	 * The default root directory where models should be stored.
81  	 */
82  	public static final String DEFAULT_ROOT = "target" + File.separator //$NON-NLS-1$
83  	        + "temp"; //$NON-NLS-1$
84  
85  	/**
86  	 * The default name of the directory where models are stored.
87  	 */
88  	public static final String DEFAULT_FOLDER = "model"; //$NON-NLS-1$
89  
90  	/**
91  	 * The dafault path to the directory where models should be stored.
92  	 */
93  	public static final String DEFAULT_PATH = DEFAULT_ROOT + File.separator + DEFAULT_FOLDER + File.separator;
94  
95  	private Mapper() {
96  		if (useDb) {
97  			try {
98  				String[] props = mysqlProps;
99  				Class.forName(props[0]);
100 				String url = props[1];
101 				conn = DriverManager.getConnection(url, props[2], props[3]);
102 				// TODO transakcje
103 				// conn.setAutoCommit(false);
104 				dbPresent = true;
105 			} catch (ClassNotFoundException e) {
106 				log.info("Data Base is not present. Using XML persister."); //$NON-NLS-1$
107 			} catch (SQLException e) {
108 				log.error(e);
109 				log.info("Check the DB configuration"); //$NON-NLS-1$
110 				log.info("See plugins/base/db/mysql_init.sql for details"); //$NON-NLS-1$
111 			}
112 		}
113 	}
114 
115 	/**
116 	 * Indicated if the Mapper was properly initialized (i.e. the connection with the DB is established).
117 	 *
118 	 * @return True if the mapper was properly initialized.
119 	 */
120 	public static boolean isDBPresent() {
121 		return getInstance().useDb && getInstance().dbPresent;
122 	}
123 
124 	/**
125 	 * Return connection to the DB.
126 	 *
127 	 * @return The connection to the DB
128 	 */
129 	Connection getConnection() {
130 		return conn;
131 	}
132 
133 	/**
134 	 * The only instance of the metamodel.
135 	 *
136 	 * @return The instance of the metamodel.
137 	 */
138 	public static Mapper getInstance() {
139 		return instance;
140 	}
141 
142 	/**
143 	 * Saves objects mapped to metamodel.
144 	 *
145 	 * @param object
146 	 *            The object to be saved
147 	 * @param project
148 	 *            The project which the object belongs to. If null, the object is stored in the default location (useful
149 	 *            for testing).
150 	 *
151 	 * @return true if save was successful
152 	 */
153 	public boolean save(Mappable object, IProject project) {
154 		return save(object, false, project);
155 	}
156 
157 	/**
158 	 * Saves objects mapped to metamodel.
159 	 *
160 	 * @param object
161 	 *            The object to be saved
162 	 * @param force
163 	 *            If true, the object is saved even if its 'saved' flag is set to true.
164 	 * @param project
165 	 *            The project which the object belongs to. If null, the object is stored in the default location (useful
166 	 *            for testing).
167 	 * @return true if save was successful
168 	 */
169 
170 	public synchronized boolean save(Mappable object, boolean force, IProject project) {
171 		Saver saver;
172 		if (dbPresent) {
173 			saver = new DBSaver(object, force);
174 		} else {
175 			saver = new XMLSaver(object, force, project);
176 		}
177 		boolean result = saver.save();
178 		if (project != null && result) {
179 			try {
180 				project.touch(null);
181 			} catch (CoreException e) {
182 				e.printStackTrace();
183 			}
184 		}
185 		return result;
186 	}
187 
188 	/**
189 	 * Close DB connection on exit.
190 	 */
191 	@Override
192 	public void finalize() {
193 		try {
194 			if (conn != null) {
195 				conn.close();
196 			}
197 			super.finalize();
198 		} catch (SQLException e) {
199 			System.err.println("Exception occured while closing connection to DB. " //$NON-NLS-1$
200 			        + e);
201 			e.printStackTrace();
202 		} catch (Throwable e) {
203 			e.printStackTrace();
204 		}
205 	}
206 
207 	/**
208 	 * Find objects mapped to the metamodel.
209 	 *
210 	 * @param klass
211 	 *            The class of the objects to be found
212 	 * @param typeMap
213 	 *            The type map used in recursive object creation.
214 	 *
215 	 *            <p>
216 	 *            Metamodel node with given name may be mapped to different model classes. This map is used to pick the
217 	 *            desired classes for nodes to be loaded.
218 	 *            </p>
219 	 *
220 	 *            <p>
221 	 *            By default
222 	 *            </p>
223 	 *            <ul>
224 	 *            <li>the type name of the class klass (@see pl.edu.agh.cast.metamodel.annotation.Mapping) is mapped
225 	 *            automaticaly to the klass
226 	 *            <li>the name of the node is considered a FQCN and the class is selected automatically
227 	 *            </ul>
228 	 * @param conditions
229 	 *            Conditions which should be met by initial set of nodes (if null, all nodes are loaded)
230 	 *
231 	 * @param project
232 	 *            The project where the object should be looked for.
233 	 *
234 	 * @return List of objects
235 	 */
236 	@SuppressWarnings("unchecked")
237 	public List find(Class klass, Map<String, Class> typeMap, SortedMap<String, Object> conditions, IProject project) {
238 		Loader loader;
239 		if (dbPresent) {
240 			loader = new DBLoader(objectCache, klass, typeMap, conditions);
241 		} else {
242 			loader = new XMLLoader(objectCache, klass, typeMap, conditions, project);
243 		}
244 		return loader.find();
245 	}
246 
247 	/**
248 	 * Clear the object cache.
249 	 *
250 	 */
251 	public void clearCache() {
252 		objectCache.clear();
253 	}
254 
255 	/**
256 	 * Clear the object cache.
257 	 *
258 	 * @param subLevel
259 	 *            Indicates if the sub-level cache should be clear as well.
260 	 *
261 	 */
262 	public void clearCache(boolean subLevel) {
263 		clearCache();
264 		if (subLevel && dbPresent) {
265 			Node.clearCache();
266 			Link.clearCache();
267 		}
268 	}
269 
270 	/**
271 	 * Prints statistics of the mapper cache.
272 	 */
273 	public void stats() {
274 		// TODO DO NOT USE PRINTLN
275 		// System.out.println("Object cache " + _objectCache.size());
276 		Node.stats();
277 		Link.stats();
278 	}
279 
280 	/**
281 	 * Removes object from project.
282 	 *
283 	 * @param object
284 	 *            Object to remove.
285 	 * @param project
286 	 *            The project which the object belongs to.
287 	 * @return true if removal was successful
288 	 * @throws Exception
289 	 *             When Mapper use DB persistence. Remover isn't implemented for DB persistence.
290 	 */
291 	public synchronized boolean remove(Mappable object, IProject project) throws Exception {
292 		if (dbPresent) {
293 			// no implementation for DB persistence
294 			throw new Exception("Not implemented object remover for DB persistence"); //$NON-NLS-1$
295 		} else {
296 			Remover remover = new XMLRemover(object, project);
297 			return remover.remove();
298 		}
299 
300 	}
301 }