PageRenderTime 70ms CodeModel.GetById 41ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/com/laytonsmith/PureUtilities/SerializedPersistance.java

https://github.com/zml2008/commandhelper
Java | 347 lines | 242 code | 22 blank | 83 comment | 34 complexity | a2a2852d09136d973085b0b8856f61c6 MD5 | raw file
  1. package com.laytonsmith.PureUtilities;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileNotFoundException;
  5. import java.io.FileOutputStream;
  6. import java.io.IOException;
  7. import java.io.ObjectInputStream;
  8. import java.io.ObjectOutputStream;
  9. import java.io.PrintStream;
  10. import java.io.Serializable;
  11. import java.util.ArrayList;
  12. import java.util.HashMap;
  13. import java.util.Iterator;
  14. import java.util.Map;
  15. import java.util.logging.Level;
  16. import java.util.logging.Logger;
  17. import org.bukkit.plugin.Plugin;
  18. /**
  19. * This file allows for simple data storage across many different data sources. In general, the
  20. * most common methods used are getValue and setValue. Note that getValue, setValue, save, and
  21. * load are synchronized.
  22. * @author layton
  23. */
  24. public class SerializedPersistance implements Persistance{
  25. /**
  26. * This is the data structure that the registry is stored in
  27. */
  28. private HashMap<String, Serializable> data = new HashMap<String, Serializable>();
  29. private boolean isLoaded = false;
  30. /**
  31. * The storage location of the persistance database. Note that it is package private,
  32. * so it can be changed.
  33. */
  34. File storageLocation;
  35. Object user;
  36. public SerializedPersistance(File database, Plugin user){
  37. storageLocation = database;
  38. this.user = user;
  39. }
  40. /**
  41. * Private constructor, used for testing this class
  42. * @param database
  43. * @param user
  44. */
  45. private SerializedPersistance(File database, Object user){
  46. storageLocation = database;
  47. this.user = user;
  48. }
  49. /**
  50. * Loads the database from disk. This is automatically called when setValue or getValue is called.
  51. * @throws Exception
  52. */
  53. public synchronized void load() throws Exception {
  54. try {
  55. FileInputStream fis = null;
  56. ObjectInputStream in = null;
  57. fis = new FileInputStream(storageLocation);
  58. in = new ObjectInputStream(fis);
  59. HashMap<String, Serializable> tempData = (HashMap<String, Serializable>) in.readObject();
  60. String[] myNamespace;
  61. if(user != null){
  62. myNamespace = ("plugin." + user.getClass().getCanonicalName()).split("\\.");
  63. } else {
  64. //We're running from the command line
  65. data = tempData;
  66. return;
  67. }
  68. Iterator i = tempData.entrySet().iterator();
  69. while (i.hasNext()) {
  70. String[] key = ((Map.Entry)i.next()).getKey().toString().split("\\.");
  71. boolean match = true;
  72. for(int j = 0; j < myNamespace.length; j++){
  73. if(key.length > myNamespace.length){
  74. if(!key[j].equals(myNamespace[j])){
  75. match = false;
  76. break;
  77. }
  78. }
  79. }
  80. if(match){
  81. data.put(getNamespace(key), tempData.get(getNamespace(key)));
  82. }
  83. }
  84. in.close();
  85. isLoaded = true;
  86. } catch (FileNotFoundException ex){
  87. //ignore this one
  88. } catch (Exception ex) {
  89. throw ex;
  90. }
  91. }
  92. /**
  93. * Causes the database to be saved to disk
  94. * @throws IOException
  95. */
  96. public synchronized void save() throws Exception {
  97. try {
  98. HashMap<String, Serializable> tempData;
  99. try{
  100. FileInputStream fis = null;
  101. ObjectInputStream in = null;
  102. fis = new FileInputStream(storageLocation);
  103. in = new ObjectInputStream(fis);
  104. tempData = (HashMap<String, Serializable>) in.readObject();
  105. } catch(FileNotFoundException ex){
  106. tempData = new HashMap<String, Serializable>();
  107. }
  108. Iterator i = data.entrySet().iterator();
  109. ArrayList<String> toRemove = new ArrayList<String>();
  110. while (i.hasNext()) {
  111. String key = ((Map.Entry)i.next()).getKey().toString();
  112. if(data.get(key) == null){
  113. tempData.remove(key);
  114. toRemove.add(key);
  115. } else{
  116. tempData.put(key, data.get(key));
  117. }
  118. }
  119. for(String s : toRemove){
  120. data.remove(s);
  121. }
  122. FileOutputStream fos = null;
  123. ObjectOutputStream out = null;
  124. storageLocation.getParentFile().mkdirs();
  125. if(!storageLocation.exists())
  126. storageLocation.createNewFile();
  127. fos = new FileOutputStream(storageLocation);
  128. out = new ObjectOutputStream(fos);
  129. out.writeObject(tempData);
  130. out.close();
  131. System.out.println("Persistance saved into " + this.hashCode());
  132. } catch (Exception ex) {
  133. throw ex;
  134. }
  135. }
  136. /**
  137. * You should not usually use this method. Please see <code>setValue(String[] key, Serializable value)</code>
  138. */
  139. private synchronized Object setValue(String key, Serializable value) {
  140. //defer loading until we actually try and use the data structure
  141. if (isLoaded == false) {
  142. System.out.println("Loading values for " + user.getClass().getCanonicalName());
  143. try {
  144. load();
  145. } catch (Exception ex) {
  146. Logger.getLogger("Minecraft").log(Level.SEVERE, null, ex);
  147. }
  148. }
  149. key = "plugin." + user.getClass().getCanonicalName() + "." + key;
  150. Serializable oldVal = data.get(key);
  151. data.put(key, value);
  152. return oldVal;
  153. }
  154. private synchronized Object getValue(String key) {
  155. //defer loading until we actually try and use the data structure
  156. if (isLoaded == false) {
  157. System.out.println("Loading values for " + user.getClass().getCanonicalName());
  158. try {
  159. load();
  160. } catch (Exception ex) {
  161. Logger.getLogger(SerializedPersistance.class.getName()).log(Level.SEVERE, null, ex);
  162. }
  163. }
  164. key = "plugin." + user.getClass().getCanonicalName() + "." + key;
  165. if(data == null){
  166. return null;
  167. }
  168. return data.get(key);
  169. }
  170. /**
  171. * Adds or modifies the value of the key. Typically, this convention should be followed:
  172. * <pre>
  173. * key1.key2.key3...
  174. * </pre>
  175. * To make this usage easier, the function automatically namespaces the values for you. A sample
  176. * usage might be:
  177. * <pre>
  178. * setValue(new String[]{"playerName", "value"}, value);
  179. * </pre>
  180. *
  181. * When using namespaces in this way, the isNamespaceSet function becomes available to you.
  182. * Since plugin values are global, you can use this to interact with other plugins. Caution should
  183. * be used when interacting with other plugin's values though.
  184. * @param key The key for this particular value
  185. * @param value The value to store. If value is null, the key is simply removed.
  186. * @return The object that was in this key, or null if the value did not exist.
  187. */
  188. public synchronized Object setValue(String[] key, Object value) {
  189. return setValue(getNamespace(key), (Serializable) value);
  190. }
  191. /**
  192. * Returns the value of a particular key
  193. * @param key
  194. * @return
  195. */
  196. public synchronized Object getValue(String[] key) {
  197. return getValue(getNamespace(key));
  198. }
  199. /**
  200. * Checks to see if a particular key is set. Unlike isNamespaceSet, this requires that
  201. * the exact key be specified to see if it exists.
  202. * @param key
  203. * @return
  204. */
  205. public synchronized boolean isKeySet(String[] key) {
  206. String k = getNamespace(key);
  207. k = "plugin." + user.getClass().getCanonicalName() + "." + k;
  208. return data.containsKey(k);
  209. }
  210. /**
  211. * Returns whether or not a particular namespace value is set. For instance, if the
  212. * value plugin.myPlugin.players.playerName.data is set, then the call to
  213. * <code>isNamespaceSet(new String[]{"plugin", "myPlugin"})</code> would return
  214. * <code>true</code>
  215. * @param partialKey
  216. * @return
  217. */
  218. public synchronized boolean isNamespaceSet(String[] partialKey) {
  219. String m = getNamespace(partialKey);
  220. m = "plugin." + user.getClass().getCanonicalName() + "." + m;
  221. partialKey = m.split("\\.");
  222. Iterator i = data.entrySet().iterator();
  223. while (i.hasNext()) {
  224. String key = ((Map.Entry)i.next()).getKey().toString();
  225. String[] namespace = key.split("\\.");
  226. boolean match = true;
  227. for (int k = 0; k < partialKey.length; k++) {
  228. if (namespace.length < k) {
  229. match = false;
  230. continue;
  231. }
  232. if (!namespace[k].equals(partialKey[k])) {
  233. match = false;
  234. continue;
  235. }
  236. }
  237. if (match) {
  238. return true;
  239. }
  240. }
  241. return false;
  242. }
  243. /**
  244. * Returns all the matched namespace entries.
  245. * @param partialKey The partial name of the keys you wish to return
  246. * @return An ArrayList of Map.Entries.
  247. */
  248. public synchronized ArrayList<Map.Entry> getNamespaceValues(String[] partialKey){
  249. ArrayList<Map.Entry> matches = new ArrayList<Map.Entry>();
  250. String m = getNamespace(partialKey);
  251. m = "plugin." + user.getClass().getCanonicalName() + "." + m;
  252. partialKey = m.split("\\.");
  253. if(!isLoaded){
  254. try {
  255. load();
  256. } catch (Exception ex) {
  257. Logger.getLogger(SerializedPersistance.class.getName()).log(Level.SEVERE, null, ex);
  258. }
  259. }
  260. Iterator i = data.entrySet().iterator();
  261. while (i.hasNext()) {
  262. Map.Entry entry = (Map.Entry)i.next();
  263. String key = entry.getKey().toString();
  264. String[] namespace = key.split("\\.");
  265. boolean match = true;
  266. for (int k = 0; k < partialKey.length; k++) {
  267. if (namespace.length < partialKey.length) {
  268. match = false;
  269. continue;
  270. }
  271. if (!namespace[k].equals(partialKey[k])) {
  272. match = false;
  273. continue;
  274. }
  275. }
  276. if (match) {
  277. matches.add(entry);
  278. }
  279. }
  280. return matches;
  281. }
  282. /**
  283. * Combines the String array into a single string
  284. * @param key
  285. * @return
  286. */
  287. private synchronized static String getNamespace(String[] key) {
  288. StringBuilder b = new StringBuilder();
  289. for (int i = 0; i < key.length; i++) {
  290. if (i > 0) {
  291. b.append(".").append(key[i]);
  292. } else {
  293. b.append(key[i]);
  294. }
  295. }
  296. return b.toString();
  297. }
  298. /**
  299. * Prints all of the stored values to the specified print stream.
  300. */
  301. public synchronized void printValues(PrintStream out) {
  302. try {
  303. out.println("Printing all persisted values:");
  304. load();
  305. Iterator i = data.entrySet().iterator();
  306. while (i.hasNext()) {
  307. Map.Entry e = ((Map.Entry) i.next());
  308. out.println(e.getKey()
  309. + ": " + data.get(e.getKey().toString()).toString());
  310. }
  311. out.println("Done printing persisted values");
  312. } catch (Exception ex) {
  313. Logger.getLogger(SerializedPersistance.class.getName()).log(Level.SEVERE, null, ex);
  314. }
  315. }
  316. public static void main(String[] args) throws Exception{
  317. SerializedPersistance p = new SerializedPersistance(new File("plugins/CommandHelper/persistance.ser"), new Object());
  318. p.setValue(new String[]{"player", "wraithguard01", "name"}, "wraithguard01");
  319. p.setValue(new String[]{"player", "wraithguard01", "age"}, "22");
  320. p.setValue(new String[]{"player", "other", "name"}, "other");
  321. System.out.println(p.getNamespaceValues(new String[]{"player", "wraithguard01", "age"}));
  322. System.out.println();
  323. p.save();
  324. }
  325. }