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 }