package org.archive.petabox; import java.io.IOException; import java.io.Reader; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import org.mortbay.util.ajax.JSON; /** * Petabox Item metadata. * Currently not designed for general use - Only useful for PetaboxFileSystem. * @contributer Kenji Nagahashi */ public class ItemMetadata { String server; String d1; String d2; String dir; String[] collection; Map<String, String> properties; // created and updated are related to metadata API's cache // management, rather than to modification of items. to be // removed soon. long created; long updated; long addeddate; ItemFile[] files; boolean solo; // public ItemMetadata(JSONObject jo) { // this.server = jo.optString("server"); // this.d1 = jo.optString("d1"); // this.d2 = jo.optString("d2"); // this.created = Long.parseLong(jo.optString("created", "0")); // this.updated = Long.parseLong(jo.optString("updated", "0")); // this.properties = new HashMap<String, String>(); // JSONObject joprops = jo.optJSONObject("metadata"); // if (joprops != null) { // for (String k : JSONObject.getNames(joprops)) { // // all metadata/* except for collection has string value. // if (k.equals("collection")) { // JSONArray colls = joprops.optJSONArray(k); // if (colls != null) { // collection = new String[colls.length()]; // for (int i = 0; i < collection.length; i++) { // collection[i] = colls.optString(i); // } // } // } else { // this.properties.put(k, joprops.optString(k)); // } // } // } // JSONArray jofiles = jo.optJSONArray("files"); // if (jofiles != null) { // this.files = new ItemFile[jofiles.length()]; // for (int i = 0; i < jofiles.length(); i++) { // JSONObject jofile = jofiles.optJSONObject(i); // if (jofile != null) { // try { // this.files[i] = new ItemFile(jofile); // } catch (JSONException ex) { // } // } // } // } // } final static String getString(Map<String, Object> map, String key) { Object o = map.get(key); return o != null ? o.toString() : null; } final static long parseLong(String o) { if (o == null || o.equals("")) return 0; try { return Long.parseLong(o); } catch (NumberFormatException ex) { return 0; } } final static long parseLong(Object o) { return parseLong(o != null ? o.toString() : null); } final static boolean getBoolean(Map<String, Object> map, String key, boolean defaultValue) { Object o = map.get(key); if (o instanceof Boolean) { return (Boolean)o; } else { return defaultValue; } } final static boolean getBoolean(Map<String, Object> map, String key) { return getBoolean(map, key, false); } final static long parseDateString(Object o) { if (o == null) return 0; DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"); try { Date d = df.parse(o.toString() + " +0000"); return d.getTime(); } catch (ParseException ex) { return 0; } } @SuppressWarnings("unchecked") public ItemMetadata(Map<String, Object> jo) { // metadata API returns empty object ("{}") for non-existent item. // this can happen when item lookup is out of sync with actual system // (item deleted/lost, confused during shuffling, etc.). detect this // early and don't fail. if (jo.isEmpty()) return; this.server = getString(jo, "server"); // for helping debug metadata API. if (this.server == null) { // LOG.warn("jo=" + JSON.toString(jo)); } this.d1 = getString(jo, "d1"); this.d2 = getString(jo, "d2"); this.created = parseLong(jo.get("created")); this.updated = parseLong(jo.get("updated")); this.solo = getBoolean(jo, "solo"); this.properties = new HashMap<String, String>(); Map<String, Object> joprops = (Map<String, Object>)jo.get("metadata"); if (joprops != null) { for (String k : joprops.keySet()) { // all metadata/* except for collection has string value. if (k.equals("collection")) { // collection member is a string if there's only one collection. Object collection = joprops.get(k); if (collection instanceof String) { this.collection = new String[] { (String)collection }; } else if (collection != null) { Object[] colls = (Object[])collection; if (colls != null) { this.collection = new String[colls.length]; for (int i = 0; i < this.collection.length; i++) { this.collection[i] = colls[i].toString(); } } } } else if (k.equals("addeddate")) { this.addeddate = parseDateString(joprops.get("addeddate")); } else { this.properties.put(k, joprops.get(k).toString()); } } } Object[] jofiles = (Object[])jo.get("files"); if (jofiles != null) { this.files = new ItemFile[jofiles.length]; for (int i = 0; i < jofiles.length; i++) { Map<String, Object> jofile = (Map<String, Object>)jofiles[i]; if (jofile != null) { this.files[i] = new ItemFile(jofile); } } } } @SuppressWarnings("unchecked") public ItemMetadata(Reader reader) throws /*JSONException, */IOException { //this(new JSONObject(new JSONTokener(reader))); this((Map<String, Object>)JSON.parse(reader)); } public boolean isCollection() { return properties != null && "collection".equals(properties.get("mediatype")); } public long getUpdated() { return updated; } public long getAddedDate() { return addeddate; } public boolean isSolo() { return solo; } public ItemFile[] getFiles() { return files; } public String getD1() { return d1; } public String getD2() { return d2; } public String getServer() { return server; } }