/** * Called by makePathQueryForCollection * * @param webConfig the webConfig * @param model the object model * @param object the InterMineObject * @param field the name of the field for the collection in the InterMineObject * @param sr the list of classes and subclasses * @return a PathQuery */ private static PathQuery makePathQueryForCollectionForClass( WebConfig webConfig, Model model, InterMineObject object, String field, List<Class<?>> sr) { Class<?> commonClass = CollectionUtil.findCommonSuperclass(sr); String typeOfCollection = TypeUtil.unqualifiedName(DynamicUtil.getSimpleClassName(commonClass)); String startClass = TypeUtil.unqualifiedName(DynamicUtil.getSimpleClassName(object.getClass())); String collectionPath = startClass + "." + field; PathQuery pathQuery = getQueryWithDefaultView(typeOfCollection, model, webConfig, collectionPath); pathQuery.addConstraint(Constraints.eq(startClass + ".id", object.getId().toString())); return pathQuery; }
/** * Create a PathQuery to get results for a collection of items from an InterMineObject * * @param webConfig the WebConfig * @param os the production ObjectStore * @param object the InterMineObject * @param referencedClassName the collection type * @param field the name of the field for the collection in the InterMineObject * @return a PathQuery */ public static PathQuery makePathQueryForCollection( WebConfig webConfig, ObjectStore os, InterMineObject object, String referencedClassName, String field) { String className = TypeUtil.unqualifiedName(DynamicUtil.getSimpleClassName(object.getClass())); Path path; try { path = new Path(os.getModel(), className + "." + field); } catch (PathException e) { throw new IllegalArgumentException( "Could not build path for \"" + className + "." + field + "\"."); } List<Class<?>> types = new ArrayList<Class<?>>(); if (path.endIsCollection()) { CollectionDescriptor end = (CollectionDescriptor) path.getEndFieldDescriptor(); // Only look for types if the refClass exactly matches the path type. if (end.getReferencedClassName().equals(referencedClassName)) { types = queryForTypesInCollection(object, field, os); } if (types.isEmpty()) { // the collection was empty, but still generate a query with the collection type types.add(os.getModel().getClassDescriptorByName(referencedClassName).getType()); } } else if (path.endIsReference()) { types.add(path.getLastClassDescriptor().getType()); } return makePathQueryForCollectionForClass(webConfig, os.getModel(), object, field, types); }
/** * Return a list of string paths that are defined as WebConfig to be shown in results. This will * include only attributes of the given class and not follow references. Optionally provide a * prefix to for creating a view for references/collections. * * @param type the class name to create a view for * @param model the model * @param webConfig we configuration * @param startingPath a path to prefix the class, can be null * @return the configured view paths for the class */ public static List<String> getDefaultViewForClass( String type, Model model, WebConfig webConfig, String startingPath) { String prefix = startingPath; List<String> view = new ArrayList<String>(); ClassDescriptor cld = model.getClassDescriptorByName(type); List<FieldConfig> fieldConfigs = getClassFieldConfigs(webConfig, cld); if (!StringUtils.isEmpty(prefix)) { try { // we can't add a subclass constraint, type must be same as the end of the prefix Path prefixPath = new Path(model, prefix); String prefixEndType = TypeUtil.unqualifiedName(prefixPath.getEndType().getName()); if (!prefixEndType.equals(type)) { throw new IllegalArgumentException( "Mismatch between end type of prefix: " + prefixEndType + " and type parameter: " + type); } } catch (PathException e) { LOG.error("Invalid path configured in webconfig for class: " + type); } } else { prefix = type; } for (FieldConfig fieldConfig : fieldConfigs) { String relPath = fieldConfig.getFieldExpr(); // only add attributes, don't follow references, following references can be problematic // when subclasses get involved. if (fieldConfig.getShowInResults()) { try { Path path = new Path(model, prefix + "." + relPath); // use type (e.g. Protein) not prefix (e.g. Gene.proteins) to do // attribute check Path checkIsOnlyAttribute = new Path(model, type + "." + relPath); if (checkIsOnlyAttribute.isOnlyAttribute()) { view.add(path.getNoConstraintsString()); } } catch (PathException e) { LOG.error("Invalid path configured in webconfig for class: " + type); } } } if (view.size() == 0) { for (AttributeDescriptor att : cld.getAllAttributeDescriptors()) { if (!"id".equals(att.getName())) { view.add(prefix + "." + att.getName()); } } } return view; }
/** * Return a List of Class objects corresponding to the fields returned by * getColumnFieldDescriptors(). * * @return the Class objects */ public List getColumnFieldClasses() { if (columnFieldClasses == null) { columnFieldClasses = new ArrayList(); for (int i = 0; i < columnFieldDescriptors.size(); i++) { AttributeDescriptor ad = (AttributeDescriptor) columnFieldDescriptors.get(i); if (ad == null) { columnFieldClasses.add(null); } else { String className = ad.getType(); columnFieldClasses.add(TypeUtil.instantiate(className)); } } } return columnFieldClasses; }
/** * Add a contains constraint to Query (q) built with the query class and attribute given in input * * @param query The query to add a reference to. * @param qc The class the reference belongs to. * @param attribute the name of the field of the class. * @param attributePath Another similarly named field - I wish it had been documented! * @return The query class of the attributePath. */ protected QueryClass addReference( final Query query, final QueryClass qc, String attribute, String attributePath) { ConstraintSet cs = (ConstraintSet) query.getConstraint(); QueryReference qr = null; String type = ""; boolean useSubClass = false; if (WidgetConfigUtil.isPathContainingSubClass(os.getModel(), attribute)) { useSubClass = true; type = attribute.substring(attribute.indexOf("[") + 1, attribute.indexOf("]")); attribute = attribute.substring(0, attribute.indexOf("[")); } QueryClass qcTmp = null; try { qr = new QueryObjectReference(qc, attribute); if (useSubClass) { try { qcTmp = new QueryClass(Class.forName(os.getModel().getPackageName() + "." + type)); } catch (ClassNotFoundException cnfe) { LOG.error("The type " + type + " doesn't exist in the model."); } } else { qcTmp = new QueryClass(qr.getType()); } } catch (IllegalArgumentException e) { // Not a reference - try collection instead qr = new QueryCollectionReference(qc, attribute); if (useSubClass) { try { qcTmp = new QueryClass(Class.forName(os.getModel().getPackageName() + "." + type)); } catch (ClassNotFoundException cnfe) { LOG.error("The type " + type + " doesn't exist in the model."); } } else { qcTmp = new QueryClass(TypeUtil.getElementType(qc.getType(), attribute)); } } QueryClass ret; if (!queryClassInQuery.containsKey(attributePath)) { ret = qcTmp; query.addFrom(ret); cs.addConstraint(new ContainsConstraint(qr, ConstraintOp.CONTAINS, ret)); queryClassInQuery.put(attributePath, ret); } else { ret = queryClassInQuery.get(attributePath); } return ret; }
/** * Used for making a query for a reference or collection. Only used when a user clicks on [show * all] under an inline table on an Object's report page. The type of that object is * "startingPath", eg. Department. This path will be prepended to every path in the query. The * "type" is the type of the reference/collection, eg. Employee. * * <p>TODO use getDefaultViewForClass() instead * * @param objType class of object we are querying for eg. Manager * @param model the model * @param webConfig the webconfig * @param fieldType the type of the field this object is in, eg Employee * @return query, eg. Department.employees.name */ protected static PathQuery getQueryWithDefaultView( String objType, Model model, WebConfig webConfig, String fieldType) { String prefix = fieldType; PathQuery query = new PathQuery(model); ClassDescriptor cld = model.getClassDescriptorByName(objType); List<FieldConfig> fieldConfigs = getClassFieldConfigs(webConfig, cld); if (!StringUtils.isBlank(prefix)) { try { // if the type is different to the end of the prefix path, add a subclass constraint Path fieldPath = new Path(model, fieldType); String fieldEndType = TypeUtil.unqualifiedName(fieldPath.getEndType().getName()); if (!fieldEndType.equals(objType)) { query.addConstraint(Constraints.type(fieldType, objType)); } } catch (PathException e) { LOG.error("Invalid path configured in webconfig for class: " + objType); } } for (FieldConfig fieldConfig : fieldConfigs) { if (fieldConfig.getShowInResults()) { String path = prefix + "." + fieldConfig.getFieldExpr(); int from = prefix.length() + 1; while (path.indexOf('.', from) != -1) { int dotPos = path.indexOf('.', from); int nextDot = path.indexOf('.', dotPos + 1); String outerJoin = nextDot == -1 ? path.substring(0, dotPos) : path.substring(0, nextDot); query.setOuterJoinStatus(outerJoin, OuterJoinStatus.OUTER); from = dotPos + 1; } query.addView(path); } } if (query.getView().size() == 0) { for (AttributeDescriptor att : cld.getAllAttributeDescriptors()) { if (!"id".equals(att.getName())) { query.addView(prefix + "." + att.getName()); } } } return query; }
private void populateParentChildMap(Map<String, SOTerm> soTerms, String parentSOTermName) { String parentClsName = TypeUtil.javaiseClassName(parentSOTermName); ClassDescriptor cd = model.getClassDescriptorByName(parentClsName); if (cd == null) { LOG.error("couldn't find class in model:" + parentClsName); return; } Class<?> parentClass = cd.getType(); // all collections for gene Map<String, Class<?>> childCollections = model.getCollectionsForClass(parentClass); Set<CollectionHolder> children = new HashSet<CollectionHolder>(); // for each collection, see if this is a child class for (Map.Entry<String, Class<?>> entry : childCollections.entrySet()) { String childCollectionName = entry.getKey(); String childClassName = entry.getValue().getSimpleName(); // TODO use same method as in the oboparser // is this a child collection? e.g. transcript SOTerm soterm = soTerms.get(childClassName.toLowerCase()); if (soterm == null) { // for testing continue; } // is gene in transcript parents collection for (OntologyTerm parent : soterm.getParents()) { if (parent.getName().equals(parentSOTermName)) { CollectionHolder h = new CollectionHolder(childClassName, childCollectionName); children.add(h); } } } if (children.size() > 0) { parentToChildren.put(parentSOTermName, children); } }
/** * Fetches the equivalent object information for a whole batch of objects. * * @param batch the objects * @throws ObjectStoreException if something goes wrong */ protected void getEquivalentsFor(List<ResultsRow<Object>> batch) throws ObjectStoreException { long time = System.currentTimeMillis(); long time1 = time; boolean databaseEmpty = hints.databaseEmpty(); if (savedDatabaseEmptyFetch == -1) { savedDatabaseEmptyFetch = System.currentTimeMillis() - time; } if (databaseEmpty) { savedDatabaseEmpty++; return; } // TODO: add all the objects that are referenced by these objects, and follow primary keys // We can make use of the ObjectStoreFastCollectionsForTranslatorImpl's ability to work this // all out for us. Set<InterMineObject> objects = new HashSet<InterMineObject>(); for (ResultsRow<Object> row : batch) { for (Object object : row) { if (object instanceof InterMineObject) { InterMineObject imo = (InterMineObject) object; if (idMap.get(imo.getId()) == null) { objects.add(imo); for (String fieldName : TypeUtil.getFieldInfos(imo.getClass()).keySet()) { Object fieldValue; try { fieldValue = imo.getFieldProxy(fieldName); } catch (IllegalAccessException e) { throw new RuntimeException(e); } if ((fieldValue instanceof InterMineObject) && (!(fieldValue instanceof ProxyReference))) { objects.add((InterMineObject) fieldValue); } else if (fieldValue instanceof Collection<?>) { for (Object collectionElement : ((Collection<?>) fieldValue)) { if ((collectionElement instanceof InterMineObject) && (!(collectionElement instanceof ProxyReference))) { objects.add((InterMineObject) collectionElement); } } } } } } } } objects.removeAll(equivalents.keySet()); // Now objects contains all the objects we need to fetch data for. Map<InterMineObject, Set<InterMineObject>> results = new HashMap<InterMineObject, Set<InterMineObject>>(); for (InterMineObject object : objects) { results.put(object, Collections.synchronizedSet(new HashSet<InterMineObject>())); } Map<PrimaryKey, ClassDescriptor> pksToDo = new IdentityHashMap<PrimaryKey, ClassDescriptor>(); Map<ClassDescriptor, List<InterMineObject>> cldToObjectsForCld = new IdentityHashMap<ClassDescriptor, List<InterMineObject>>(); Map<Class<?>, List<InterMineObject>> categorised = CollectionUtil.groupByClass(objects, false); Map<ClassDescriptor, Boolean> cldsDone = new IdentityHashMap<ClassDescriptor, Boolean>(); for (Class<?> c : categorised.keySet()) { Set<ClassDescriptor> classDescriptors = model.getClassDescriptorsForClass(c); for (ClassDescriptor cld : classDescriptors) { if (!cldsDone.containsKey(cld)) { cldsDone.put(cld, Boolean.TRUE); Set<PrimaryKey> keysForClass; if (source == null) { keysForClass = new HashSet<PrimaryKey>(PrimaryKeyUtil.getPrimaryKeys(cld).values()); } else { keysForClass = DataLoaderHelper.getPrimaryKeys(cld, source, lookupOs); } if (!keysForClass.isEmpty()) { time = System.currentTimeMillis(); boolean classNotExists = hints.classNotExists(cld.getType()); String className = Util.getFriendlyName(cld.getType()); if (!savedTimes.containsKey(className)) { savedTimes.put(className, new Long(System.currentTimeMillis() - time)); } if (!classNotExists) { // LOG.error("Inspecting class " + className); List<InterMineObject> objectsForCld = new ArrayList<InterMineObject>(); for (Map.Entry<Class<?>, List<InterMineObject>> category : categorised.entrySet()) { if (cld.getType().isAssignableFrom(category.getKey())) { objectsForCld.addAll(category.getValue()); } } cldToObjectsForCld.put(cld, objectsForCld); // So now we have a list of objects for this CLD. for (PrimaryKey pk : keysForClass) { // LOG.error("Adding pk " + cld.getName() + "." + pk.getName()); pksToDo.put(pk, cld); } } else { // LOG.error("Empty class " + className); } } } } } doPks(pksToDo, results, cldToObjectsForCld, time1); batchQueried += results.size(); equivalents.putAll(results); }