| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.uima.ducc.database; |
| |
| import org.apache.uima.ducc.common.utils.DuccLogger; |
| |
| import com.datastax.driver.core.BoundStatement; |
| import com.datastax.driver.core.PreparedStatement; |
| import com.datastax.driver.core.ResultSet; |
| import com.datastax.driver.core.SimpleStatement; |
| |
| public class DbHandle |
| { |
| private DuccLogger logger = null; |
| |
| DbManager manager; |
| |
| DbHandle(DbManager manager) |
| { |
| logger = DuccLogger.getLogger(DbHandle.class, "DB"); |
| // if ( DuccService.getDuccLogger() == null ) { |
| // // not running within a ducc service - just get a regular logger |
| // logger = DuccLogger.getLogger(DbHandle.class, "DB"); |
| // } else { |
| // // running within a ducc service - get the component logger |
| // logger = DuccService.getDuccLogger(DbHandle.class.getName()); |
| // } |
| this.manager = manager; |
| } |
| |
| public ResultSet execute(String sql) |
| throws Exception |
| { |
| String methodName = "execute"; |
| long now = System.currentTimeMillis(); |
| ResultSet ret = manager.execute(sql); |
| if ( logger.isDebug() ) logger.debug(methodName, null, "Time to execute", System.currentTimeMillis() - now); |
| |
| return ret; |
| } |
| |
| public ResultSet execute(SimpleStatement s) |
| { |
| return manager.execute(s); |
| } |
| |
| public ResultSet execute(BoundStatement s) |
| { |
| return manager.execute(s); |
| } |
| |
| ResultSet execute(PreparedStatement ps, Object ... fields) |
| throws Exception |
| { |
| String methodName = "execute"; |
| long now = System.currentTimeMillis(); |
| |
| try { |
| BoundStatement boundStatement = new BoundStatement(ps); |
| BoundStatement bound = boundStatement.bind(fields); |
| return execute(bound); |
| } finally { |
| if ( logger.isTrace() ) { |
| logger.trace(methodName, null, "Time to execute prepared statement:", ps.getQueryString(), System.currentTimeMillis() - now); |
| StringBuffer buf = new StringBuffer("Fields for statement: "); |
| for ( Object o: fields ) { |
| buf.append(o.toString()); |
| buf.append(" "); |
| } |
| logger.trace(methodName, null, buf.toString()); |
| } |
| } |
| } |
| |
| /** |
| * Delete the object of the indicated type and duccid. We optionally commit in case we want to |
| * do more things that have to work under the same transaction so we can rollback if needed.= |
| * |
| * Nobody is deleting; everything is moved to history. Later may be utilities to do some cleanup |
| * and we'll bring it back. |
| */ |
| // public void deleteObject(DbVertex type, Long duccid, boolean commit) |
| // throws Exception |
| // { |
| // String methodName = "deleteObject"; |
| // // there usually should only be ONE of these but the API is defined in terms of many |
| // // TODO: throw and rollback if more than one object ( I think, let's revisit this ) |
| // Iterable<Vertex> s = graphDb.getVertices(type.pname(), new String[] {"@class", DbConstants.DUCCID}, new Object[]{type.pname(), duccid}); |
| // for ( Vertex v : s ) { |
| // //logger.info(methodName, null, "Delete vertex for class", type, "id", duccid, "commit", commit); |
| // graphDb.removeVertex(v); |
| // } |
| |
| // if ( commit ) graphDb.commit(); |
| // } |
| |
| /** |
| * Plop the object into the DB under the class indicated by 'type', with the |
| * unique key 'duccid'. |
| * |
| * We use id + isHistory + vertex class = primary key and hence must insure they're always set. |
| * |
| * @prarm type The type enum of the thing to save (e.g. Job) |
| * @param duccid The numeric ducc id of the object |
| * @param obj The json-ified object to save |
| * @param isHistory 'true' if we save to history, 'false' otherwise |
| */ |
| // public OrientVertex saveObject(DbVertex type, Long duccid, String obj, DbCategory dbcat) |
| // { |
| // //String methodName = "saveObject"; |
| |
| // //String typename = type.pname(); |
| |
| // OrientVertex ret = null; |
| // ODocument document = null; |
| // document = new ODocument(type.pname()); |
| // ret = new OrientVertex(graphDb, document); |
| |
| // document.fromJSON(obj); |
| // document.field(DbConstants.DUCCID, duccid); |
| // document.field(DbConstants.DUCC_DBCAT, dbcat.pname()); |
| // graphDb.getRawGraph().save(document); |
| |
| // return ret; |
| // } |
| |
| |
| /** |
| * Helper class for retrieving an object and all the stuff it points to. e.g. if you want to |
| * reconstitue a DuccWorkJob you need to chase the edges to get the process map and the jd and |
| * probably other stuff. |
| * |
| * We don't care about history here because the call will have done the right search first. |
| * |
| * @param v The vertex discovered by the caller. |
| * @param read_all 'true' to do recursive traversal down the edges, false otherwise. |
| * |
| * NOTE: I think the db may have a primitive to do this traversal, |
| * @TODO must research and use it as it will likely be safer and more efficient. |
| * |
| */ |
| // private DbObject traverseObject(OrientVertex v, boolean read_all) |
| // { |
| // //String methodName = "traverseObject"; |
| // ODocument doc = v.getRecord(); |
| // String doc_json = doc.toJSON(); |
| // String stype = v.getProperty("@class"); |
| // DbVertex type = manager.vertexType(stype); |
| |
| // DbObject ret = new DbObject(doc_json, type); |
| |
| // if ( read_all ) { |
| // Iterable<Edge> ed = v.getEdges(Direction.OUT); |
| // for ( Edge e : ed ) { |
| // OrientEdge oe = (OrientEdge) e; |
| // OrientVertex ov = oe.getVertex(Direction.IN); |
| // //logger.info(methodName, null, "Found edge connected to vertex of type", ov.getProperty("@class"), "duccid", ov.getProperty(DUCCID)); |
| // ret.addEmbedded(traverseObject(ov, read_all)); |
| // } |
| // } |
| // return ret; |
| // } |
| |
| /** |
| * Read a database object, optionally chasing edges to get all the various bits. |
| * |
| * @param type The type enum of the object, e.g. "Job" |
| * @param duccid The numeric id of the object |
| * @param read_all 'true' to recursively chase down the edges, 'false' otherwise. |
| */ |
| // public DbObject readObject(DbVertex type, Long duccid, boolean read_all) |
| // { |
| // String methodName = "readObject"; |
| // Iterable<Vertex> s = graphDb.getVertices(type.pname(), new String[] {"@class", DbConstants.DUCCID}, new Object[]{type.pname(), duccid}); |
| // int count = 0; |
| // OrientVertex fv = null; |
| // for (Vertex v : s) { |
| // fv = (OrientVertex) v; |
| // //logger.info(methodName, null, "from vertex", count, fv.getIdentity()); |
| // count++; |
| // } |
| // if ( count > 1 ) { |
| // logger.error(methodName, null, "Expected unique object, found", count, "objects. Returning only the first object."); |
| // } |
| |
| // //logger.info(methodName, null, "Traversing", fv.getProperty("@class"), "duccid", fv.getProperty(DUCCID)); |
| // return traverseObject(fv, read_all); |
| // } |
| |
| /** |
| * This views a row as a set of properties. We update a single column in the table. |
| * |
| * @param table The table name. |
| * @param row The key to search on for update. Caller must fully-form it e.g. "name=bob", if the key |
| * field is called 'name'. |
| * @param propkey The name of the column. |
| * @param propval The value to replace the existing value. |
| */ |
| public boolean updateProperty(String table, String row, String propkey, Object propval) |
| throws Exception |
| { |
| String methodName = "updateProperty"; |
| long now = System.currentTimeMillis(); |
| |
| String cql = "UPDATE " + table + " SET " + propkey + "=" + propval + " WHERE " + row; |
| try { |
| manager.execute(cql); |
| return true; |
| } finally { |
| logger.debug(methodName, null, "Time to update one property", propkey, System.currentTimeMillis() - now); |
| } |
| } |
| |
| /** |
| * This views a row as a set of properties. We update multiple columns in a single row of the table. |
| * |
| * @param table The table name. |
| * @param row The key to search on for update. Caller must fully-form it e.g. "name=bob", if the key |
| * field is called 'name'. |
| * @param props This is a list of propertes where every even-numbered object is a column name and |
| * every odd-numbered object is its value. |
| * |
| * @throws IllegalArgumentException if the number of 'props' is not even. Lower layers may throw |
| * unchecked exceptions also. |
| */ |
| public void updateProperties(String table, String row, Object... props) |
| throws Exception |
| { |
| String methodName = "updateProperties"; |
| long now = System.currentTimeMillis(); |
| |
| if ( ( props.length % 2 ) != 0 ) { |
| throw new IllegalArgumentException("mkUpdate: need even number of props to form (k,v) list. Found " + props.length + " props."); |
| } |
| |
| String cql = DbUtil.mkUpdate(table, row, props); |
| try { |
| logger.trace(methodName, null, cql); |
| manager.execute(cql); |
| } finally { |
| logger.debug(methodName, null, "Total time to update properties", System.currentTimeMillis() - now); |
| } |
| } |
| |
| |
| PreparedStatement prepare(String cql) |
| { |
| //String methodName = "prepare"; |
| return manager.prepare(cql); |
| } |
| |
| void truncate(String table) |
| throws Exception |
| { |
| manager.truncate(table); |
| } |
| |
| |
| void saveObject(PreparedStatement ps, Object ... fields) |
| throws Exception |
| { |
| String methodName = "saveObject"; |
| long now = System.currentTimeMillis(); |
| |
| BoundStatement boundStatement = new BoundStatement(ps); |
| BoundStatement bound = boundStatement.bind(fields); |
| execute(bound); |
| logger.debug(methodName, null, "Time to execute prepared statement:", ps.getQueryString(), System.currentTimeMillis() - now); |
| } |
| |
| /** |
| * Create an object in the db from a properties object. The caller must do the the checking to insure |
| * the object already exists (or not, e.g. for a db loader). |
| * |
| * @param props The properties object to be placed in the db. |
| * @param type The type enum for the object, e.g. "Service" |
| * @param duccid The numeric id of the object |
| * @param isHistory 'True' if it is to be placed in history, 'false' otherwise. |
| */ |
| // public OrientVertex createProperties(String keyid, Object key, DbVertex type, DbCategory dbcat, Properties props) |
| // { |
| // String methodName = "createPropertiesObject"; |
| // String typeName = type.pname(); |
| // OrientVertex ov = null; |
| |
| // logger.info(methodName, null, "Create new properties object of type", type.pname(), "category", dbcat.pname(), "key", key); |
| // ov = graphDb.addVertex("class:" + typeName, keyid, key, DbConstants.DUCC_DBCAT, dbcat.pname()); |
| // ov.setProperties(props); |
| // return ov; |
| // } |
| |
| // static Gson gson = null; |
| // static Gson mkGsonForJob() |
| // { |
| // synchronized(DbHandle.class) { |
| // if ( gson != null ) return gson; |
| |
| // // We need to define Instance creators and such so we do it in a common place |
| // GsonBuilder gb = new GsonBuilder(); |
| |
| // GenericInterfaceAdapter customAdapter = new GenericInterfaceAdapter(); |
| // gb.serializeSpecialFloatingPointValues().setPrettyPrinting(); |
| // gb.enableComplexMapKeySerialization(); |
| |
| // gb.registerTypeAdapter(Node.class, new NodeInstanceCreator()); |
| // gb.registerTypeAdapter(NodeIdentity.class, new NodeIdentityCreator()); |
| |
| // //gb.registerTypeAdapter(IIdentity.class, new IdentityInstanceCreator()); |
| // gb.registerTypeAdapter(IIdentity.class, customAdapter); |
| |
| // gb.registerTypeAdapter(IDuccId.class, customAdapter); |
| // gb.registerTypeAdapter(ICommandLine.class, customAdapter); |
| // gb.registerTypeAdapter(ITimeWindow.class, customAdapter); |
| // gb.registerTypeAdapter(IDuccProcessWorkItems.class, customAdapter); |
| // gb.registerTypeAdapter(IDuccUimaAggregateComponent.class, customAdapter); |
| // gb.registerTypeAdapter(IUimaPipelineAEComponent.class, customAdapter); |
| // gb.registerTypeAdapter(IRationale.class, customAdapter); |
| // gb.registerTypeAdapter(IDuccUimaDeployableConfiguration.class, customAdapter); |
| // gb.registerTypeAdapter(IDuccStandardInfo.class, customAdapter); |
| // gb.registerTypeAdapter(IDuccSchedulingInfo.class, customAdapter); |
| // gb.registerTypeAdapter(IDuccPerWorkItemStatistics.class, customAdapter); |
| // gb.registerTypeAdapter(IDuccReservationMap.class, customAdapter); |
| // gb.registerTypeAdapter(JdReservationBean.class, customAdapter); |
| |
| // //ConcurrentHashMap<DuccId, Long> x = new ConcurrentHashMap<DuccId, Long>(); |
| // //gb.registerTypeAdapter(x.getClass(), new MapAdaptor()); |
| |
| // //gb.registerTypeAdapterFactory(new DuccTypeFactory()); |
| // //Object obj = new ArrayList<IJdReservation>(); |
| // //gb.registerTypeAdapter(obj.getClass(), customAdapter); |
| // Gson g = gb.create(); |
| // return g; |
| // } |
| // } |
| |
| // // ---------------------------------------------------------------------------------------------------- |
| // // Instance creators and adaptors for GSON |
| // // ---------------------------------------------------------------------------------------------------- |
| |
| // // We need these for the DuccNode and NodeIdentity because they don't have no-arg |
| // // Constructors. |
| // // |
| // // @TODO after merge, consult with Jerry about adding in those constructors |
| // private static class NodeInstanceCreator implements InstanceCreator<Node> { |
| // public Node createInstance(Type type) { |
| // // System.out.println("DuccNode"); |
| // return new DuccNode(null, null, false); |
| // } |
| // } |
| |
| // private static class NodeIdentityCreator implements InstanceCreator<NodeIdentity> { |
| // public NodeIdentity createInstance(Type type) { |
| // // System.out.println("DuccNodeIdentity"); |
| // try { return new NodeIdentity(null, null); } catch ( Exception e ) {} |
| // return null; |
| // } |
| // } |
| |
| // /** |
| // * JSON helper for our complex objects. Gson doesn't save type information in the json so |
| // * it doesn't know how to construct things declared as interfaces. |
| // * |
| // * This class is a Gson adapter that saves the actual object type in the json on serialization, |
| // * and uses that information on deserialization to construct the right thing. |
| // */ |
| // private static class GenericInterfaceAdapter |
| // implements |
| // JsonSerializer<Object>, |
| // JsonDeserializer<Object> |
| // { |
| |
| // private static final String DUCC_META_CLASS = "DUCC_META_CLASS"; |
| |
| // @Override |
| // public Object deserialize(JsonElement jsonElement, |
| // Type type, |
| // JsonDeserializationContext jsonDeserializationContext) |
| // throws JsonParseException |
| // { |
| // // Reconstitute the "right" class based on the actual class it came from as |
| // // found in metadata |
| // JsonObject obj = jsonElement.getAsJsonObject(); |
| // JsonElement clElem= obj.get(DUCC_META_CLASS); |
| |
| // if ( clElem== null ) { |
| // throw new IllegalStateException("Cannot determine concrete class for " + type + ". Must register explicit type adapter for it."); |
| // } |
| // String clName = clElem.getAsString(); |
| |
| // //System.out.println("----- elem: " + clName + " clElem: " + obj); |
| // try { |
| // Class<?> clz = Class.forName(clName); |
| // return jsonDeserializationContext.deserialize(jsonElement, clz); |
| // } catch (ClassNotFoundException e) { |
| // throw new JsonParseException(e); |
| // } |
| // } |
| |
| // @Override |
| // public JsonElement serialize(Object object, |
| // Type type, |
| // JsonSerializationContext jsonSerializationContext) |
| // { |
| // // Add the mete element indicating what kind of concrete class is this came from |
| // //String n = object.getClass().getCanonicalName(); |
| // //System.out.println("**** Serialize object A " + n + " of type " + type); |
| // //if ( n.contains("Concurrent") ) { |
| // // int stop = 1; |
| // // stop++; |
| // //} |
| |
| // JsonElement ele = jsonSerializationContext.serialize(object, object.getClass()); |
| // //System.out.println("**** Serialize object B " + object.getClass().getCanonicalName() + " of type " + type + " : ele " + ele); |
| // ele.getAsJsonObject().addProperty(DUCC_META_CLASS, object.getClass().getCanonicalName()); |
| // return ele; |
| // } |
| // } |
| |
| // @SuppressWarnings("unused") |
| // private class DuccTypeFactory |
| // implements TypeAdapterFactory |
| // { |
| |
| // public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) |
| // { |
| // //System.out.println("TYPETOKEN: " + typeToken + " raw type: " + typeToken.getRawType().getName()); |
| // Class<?> cl = typeToken.getRawType(); |
| // //System.out.println(" Canonical name: " + cl.getCanonicalName()); |
| // Type type = typeToken.getType(); |
| // if ( typeToken.getRawType() != ConcurrentHashMap.class ) { |
| // //System.out.println("Skipping type " + typeToken); |
| // return null; |
| // } |
| |
| // if ( type instanceof ParameterizedType ) { |
| |
| // ParameterizedType pt = (ParameterizedType) type; |
| // Type[] types = pt.getActualTypeArguments(); |
| // //for ( Type tt : types ) { |
| // // System.out.println(" TYPE ARGUMENTS: " + tt); |
| // //} |
| // Type tt = types[0]; |
| // Class<?> cll = (Class<?>) tt; |
| |
| // } |
| // return null; |
| // } |
| |
| // } |
| |
| // @SuppressWarnings("unused") |
| // private class MapAdaptor |
| // extends TypeAdapter<ConcurrentHashMap<DuccId, Long>> |
| // { |
| |
| // public void write(JsonWriter out, ConcurrentHashMap<DuccId, Long> map) throws IOException { |
| // System.out.println("***************** Writing"); |
| // if (map == null) { |
| // out.nullValue(); |
| // return; |
| // } |
| |
| // out.beginArray(); |
| // for (DuccId k : map.keySet() ) { |
| // out.beginObject(); |
| // out.value(k.getFriendly()); |
| // out.value(k.getUnique()); |
| // out.value(map.get(k)); |
| // out.endObject(); |
| // } |
| // out.endArray(); |
| // } |
| |
| // public ConcurrentHashMap<DuccId, Long> read(JsonReader in) throws IOException { |
| // System.out.println("***************** reading"); |
| // if (in.peek() == JsonToken.NULL) { |
| // in.nextNull(); |
| // return null; |
| // } |
| |
| // ConcurrentHashMap<DuccId, Long> ret = new ConcurrentHashMap<DuccId, Long>(); |
| // in.beginArray(); |
| // while (in.hasNext()) { |
| // in.beginObject(); |
| // Long friendly = in.nextLong(); |
| // String unique = in.nextString(); |
| |
| // Long val = in.nextLong(); |
| // in.endObject(); |
| // DuccId id = new DuccId(friendly); |
| // id.setUUID(UUID.fromString(unique)); |
| // ret.put(id, val); |
| // } |
| // in.endArray(); |
| // return ret; |
| // } |
| // } |
| } |
| |