PageRenderTime 194ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/Persistence/src/main/java/com/elmakers/mine/bukkit/persistence/Persistence.java

https://github.com/elBukkit/PersistencePlugin
Java | 445 lines | 267 code | 48 blank | 130 comment | 33 complexity | 1520bed69c04806d07ecb12501fa6936 MD5 | raw file
  1. package com.elmakers.mine.bukkit.persistence;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import java.util.Map;
  5. import java.util.concurrent.ConcurrentHashMap;
  6. import java.util.logging.Logger;
  7. import org.bukkit.Server;
  8. import com.elmakers.mine.bukkit.data.DataStore;
  9. import com.elmakers.mine.bukkit.data.DataStoreProvider;
  10. import com.elmakers.mine.bukkit.persisted.EntityInfo;
  11. import com.elmakers.mine.bukkit.persisted.Migrate;
  12. import com.elmakers.mine.bukkit.persisted.MigrationInfo;
  13. import com.elmakers.mine.bukkit.persisted.PersistClass;
  14. import com.elmakers.mine.bukkit.persistence.exception.InvalidPersistedClassException;
  15. /**
  16. * The main Persistence interface.
  17. *
  18. * This class is a singleton- use Persistence.getInstance or
  19. * PersistencePlugin.getPersistence to retrieve the instance.
  20. *
  21. * @author NathanWolf
  22. */
  23. public class Persistence implements
  24. com.elmakers.mine.bukkit.persisted.Persistence
  25. {
  26. private static boolean allowOpsSUAccess = true;
  27. // Make sure that we don't create a persisted class twice at the same time
  28. private static final Object classCreateLock = new Object();
  29. private static final Logger log = Logger.getLogger("Minecraft");
  30. /**
  31. * Retrieve the Logger that Persistence uses for debug messages and errors.
  32. *
  33. * Currently, this is hard-coded to the Minecraft server logger.
  34. *
  35. * @return A Logger that can be used for errors or debugging.
  36. */
  37. public static Logger getLogger()
  38. {
  39. return log;
  40. }
  41. public static boolean getOpsCanSU()
  42. {
  43. return allowOpsSUAccess;
  44. }
  45. public static void setOpsCanSU(boolean allow)
  46. {
  47. allowOpsSUAccess = allow;
  48. }
  49. // Locks for manual synchronization
  50. private final Map<Class<? extends Object>, PersistentClass> persistedClassMap = new ConcurrentHashMap<Class<? extends Object>, PersistentClass>();
  51. private final DataStoreProvider provider;
  52. private final Map<String, Schema> schemaMap = new ConcurrentHashMap<String, Schema>();
  53. private final Server server;
  54. /**
  55. * Persistence is a singleton, so we hide the constructor.
  56. *
  57. * Use PersistencePlugin.getInstance to retrieve a reference to Persistence
  58. * safely.
  59. *
  60. * @see PersistencePlugin#getPersistence()
  61. * @see Persistence#getInstance()
  62. */
  63. public Persistence(Server server, DataStoreProvider provider)
  64. {
  65. this.server = server;
  66. this.provider = provider;
  67. }
  68. /**
  69. * Clear all data.
  70. *
  71. * This is currently the method used to clear the cache and reload data,
  72. * however it is flawed. It will probably be replaced with a "reload" method
  73. * eventually.
  74. */
  75. public void clear()
  76. {
  77. persistedClassMap.clear();
  78. schemaMap.clear();
  79. }
  80. protected PersistentClass createPersistedClass(Class<? extends Object> persistType, EntityInfo entityInfo) throws InvalidPersistedClassException
  81. {
  82. PersistentClass persistedClass = new PersistentClass(this, entityInfo);
  83. if (!persistedClass.bind(persistType))
  84. {
  85. return null;
  86. }
  87. String schemaName = persistedClass.getSchemaName();
  88. Schema schema = getSchema(schemaName);
  89. if (schema == null)
  90. {
  91. schema = createSchema(schemaName);
  92. }
  93. schema.addPersistedClass(persistedClass);
  94. persistedClass.setSchema(schema);
  95. persistedClassMap.put(persistType, persistedClass);
  96. // Deferred bind refernces- to avoid circular reference issues
  97. persistedClass.bindReferences();
  98. return persistedClass;
  99. }
  100. protected Schema createSchema(String schemaName)
  101. {
  102. Schema schema = schemaMap.get(schemaName);
  103. if (schema == null)
  104. {
  105. schemaName = schemaName.toLowerCase();
  106. DataStore store = createStore(schemaName);
  107. schema = new Schema(schemaName, store);
  108. schemaMap.put(schemaName, schema);
  109. }
  110. return schema;
  111. }
  112. protected DataStore createStore(String schema)
  113. {
  114. return provider.createStore(schema);
  115. }
  116. public void disconnect()
  117. {
  118. for (Schema schema : schemaMap.values())
  119. {
  120. schema.disconnect();
  121. }
  122. }
  123. /*
  124. * (non-Javadoc)
  125. *
  126. * @see
  127. * com.elmakers.mine.bukkit.persistence.IPersistence#get(java.lang.Object,
  128. * java.lang.Class)
  129. */
  130. @SuppressWarnings("unchecked")
  131. public <T> T get(Object id, Class<T> objectType)
  132. {
  133. PersistentClass persistedClass = null;
  134. try
  135. {
  136. persistedClass = getPersistedClass(objectType);
  137. }
  138. catch (InvalidPersistedClassException e)
  139. {
  140. // TODO Auto-generated catch block
  141. e.printStackTrace();
  142. }
  143. if (persistedClass == null)
  144. {
  145. return null;
  146. }
  147. Object result = persistedClass.get(id);
  148. if (result == null)
  149. {
  150. return null;
  151. }
  152. return (T) result;
  153. }
  154. /*
  155. * (non-Javadoc)
  156. *
  157. * @see
  158. * com.elmakers.mine.bukkit.persistence.IPersistence#getAll(java.util.List,
  159. * java.lang.Class)
  160. */
  161. public <T> void getAll(List<T> objects, Class<T> objectType)
  162. {
  163. PersistentClass persistedClass = null;
  164. try
  165. {
  166. persistedClass = getPersistedClass(objectType);
  167. }
  168. catch (InvalidPersistedClassException e)
  169. {
  170. // TODO Auto-generated catch block
  171. e.printStackTrace();
  172. }
  173. if (persistedClass == null)
  174. {
  175. return;
  176. }
  177. persistedClass.getAll(objects);
  178. }
  179. public <T> List<T> getAll(Class<T> objectType)
  180. {
  181. PersistentClass persistedClass = null;
  182. try
  183. {
  184. persistedClass = getPersistedClass(objectType);
  185. }
  186. catch (InvalidPersistedClassException e)
  187. {
  188. // TODO Auto-generated catch block
  189. e.printStackTrace();
  190. }
  191. if (persistedClass == null)
  192. {
  193. return null;
  194. }
  195. List<T> list = new ArrayList<T>();
  196. persistedClass.getAll(list);
  197. return list;
  198. }
  199. /**
  200. * Retrieve or create a persisted class, using the annotations built into
  201. * the class.
  202. *
  203. * @param persistClass
  204. * The annotated Class to persist
  205. * @return The persisted class definition, or null if failure
  206. */
  207. public PersistentClass getPersistedClass(Class<? extends Object> persistClass) throws InvalidPersistedClassException
  208. {
  209. /*
  210. * Look for Class annotations
  211. */
  212. // TODO: Lookup from schema/name map ... hm... uh, how to do this
  213. // without the annotation?
  214. // I guess pass in one, and then other persisted classes can request
  215. // data from their own schema...
  216. PersistentClass persistedClass = persistedClassMap.get(persistClass);
  217. if (persistedClass == null)
  218. {
  219. PersistClass entityAnnotation = persistClass.getAnnotation(PersistClass.class);
  220. Migrate migrationAnnotation = persistClass.getAnnotation(Migrate.class);
  221. if (entityAnnotation == null)
  222. {
  223. throw new InvalidPersistedClassException(persistClass, "Class does not have the @PersistClass annotation");
  224. }
  225. persistedClass = getPersistedClass(persistClass, new EntityInfo(entityAnnotation));
  226. if (migrationAnnotation != null)
  227. {
  228. persistedClass.setMigrationInfo(new MigrationInfo(persistedClass, migrationAnnotation));
  229. }
  230. }
  231. return persistedClass;
  232. }
  233. /**
  234. * Retrieve or create a persisted class definition for a given class type.
  235. *
  236. * This can be used to create a persisted class based on a existing class.
  237. *
  238. * @param persistType
  239. * The Class to persist
  240. * @param entityInfo
  241. * Information on how to persist this class
  242. * @return The persisted class definition, or null if failure
  243. */
  244. public PersistentClass getPersistedClass(Class<? extends Object> persistType, EntityInfo entityInfo)
  245. {
  246. PersistentClass persistedClass = persistedClassMap.get(persistType);
  247. if (persistedClass == null)
  248. {
  249. // Lock now, to create an atomic checkCreate for class:
  250. synchronized (classCreateLock)
  251. {
  252. persistedClass = persistedClassMap.get(persistType);
  253. if (persistedClass == null)
  254. {
  255. try
  256. {
  257. persistedClass = createPersistedClass(persistType, entityInfo);
  258. }
  259. catch (InvalidPersistedClassException e)
  260. {
  261. // TODO Auto-generated catch block
  262. e.printStackTrace();
  263. }
  264. }
  265. }
  266. }
  267. return persistedClass;
  268. }
  269. /**
  270. * Retrieve a Schema definition, with a list of PersistedClasses.
  271. *
  272. * This function is used for inspecting schemas and entities.
  273. *
  274. * @param schemaName
  275. * The schema to retrieve
  276. * @return A Schema definition class, containing entity classes
  277. */
  278. public Schema getSchema(String schemaName)
  279. {
  280. return schemaMap.get(schemaName);
  281. }
  282. /**
  283. * Retrieve a list of definitions for all known schemas.
  284. *
  285. * This function is used for inspecting schemas and entities.
  286. *
  287. * @return The list of schemas
  288. */
  289. public List<Schema> getSchemaList()
  290. {
  291. List<Schema> schemaList = new ArrayList<Schema>();
  292. schemaList.addAll(schemaMap.values());
  293. return schemaList;
  294. }
  295. /*
  296. * Protected members
  297. */
  298. public Server getServer()
  299. {
  300. return server;
  301. }
  302. /*
  303. * (non-Javadoc)
  304. *
  305. * @see
  306. * com.elmakers.mine.bukkit.persistence.IPersistence#put(java.lang.Object)
  307. */
  308. public boolean put(Object persist)
  309. {
  310. if (persist == null)
  311. {
  312. return false;
  313. }
  314. PersistentClass persistedClass = null;
  315. try
  316. {
  317. persistedClass = getPersistedClass(persist.getClass());
  318. }
  319. catch (InvalidPersistedClassException e)
  320. {
  321. // TODO Auto-generated catch block
  322. e.printStackTrace();
  323. }
  324. if (persistedClass == null)
  325. {
  326. return false;
  327. }
  328. persistedClass.put(persist);
  329. return true;
  330. }
  331. /*
  332. * (non-Javadoc)
  333. *
  334. * @see
  335. * com.elmakers.mine.bukkit.persistence.IPersistence#putAll(java.util.List,
  336. * java.lang.Class)
  337. */
  338. public <T> void putAll(List<T> objects, Class<T> objectType)
  339. {
  340. PersistentClass persistedClass = null;
  341. try
  342. {
  343. persistedClass = getPersistedClass(objectType);
  344. }
  345. catch (InvalidPersistedClassException e)
  346. {
  347. // TODO Auto-generated catch block
  348. e.printStackTrace();
  349. }
  350. if (persistedClass == null)
  351. {
  352. return;
  353. }
  354. persistedClass.putAll(objects);
  355. }
  356. /*
  357. * (non-Javadoc)
  358. *
  359. * @see
  360. * com.elmakers.mine.bukkit.persistence.IPersistence#remove(java.lang.Object
  361. * )
  362. */
  363. public void remove(Object removeObject)
  364. {
  365. PersistentClass persistedClass = null;
  366. try
  367. {
  368. persistedClass = getPersistedClass(removeObject.getClass());
  369. }
  370. catch (InvalidPersistedClassException e)
  371. {
  372. // TODO Auto-generated catch block
  373. e.printStackTrace();
  374. }
  375. if (persistedClass == null)
  376. {
  377. return;
  378. }
  379. persistedClass.remove(removeObject);
  380. }
  381. /**
  382. * Force a save of all cached data.
  383. *
  384. * This only saves dirty data- unmodified data is not saved back to the
  385. * database. Persistence calls save() internally on server shutdown, player
  386. * login, and player logout. So, calling save is not mandatory- you only
  387. * need to use it to force an immediate save.
  388. *
  389. */
  390. public void save()
  391. {
  392. for (PersistentClass persistedClass : persistedClassMap.values())
  393. {
  394. persistedClass.save();
  395. }
  396. }
  397. }