/** * Constructor. * * @param jdb underlying database * @param type type restrictions, or null for none */ public TypeContainer(Permazen jdb, Class<?> type) { super(Node.class); Preconditions.checkArgument(jdb != null, "null jdb"); this.jdb = jdb; // Get the types of all JClasses assignable to the given type, and use lowest common ancestor as the "top type" final HashSet<Class<?>> types = this.jdb.getJClasses().values().stream() .filter(jclass -> type == null || type.isAssignableFrom(jclass.getType())) .map(JClass::getType) .collect(Collectors.toCollection(HashSet::new)); this.rootType = !types.isEmpty() ? Util.findLowestCommonAncestorOfClasses(types).getRawType() : Object.class; }
KeyRanges[] getPathKeyRanges() { if (this.pathKeyRanges == null) { final int numJClasses = this.jdb.jclasses.size(); final KeyRanges[] array = new KeyRanges[this.pathTypes.size()]; for (int i = 0; i < this.pathTypes.size(); i++) { final HashSet<JClass<?>> jclasses = new HashSet<>(); final Set<Class<?>> types = this.pathTypes.get(i); for (Class<?> type : types) jclasses.addAll(this.jdb.getJClasses(type)); if (jclasses.size() == numJClasses && this.isAnyAssignableFrom(types, UntypedJObject.class)) continue; // no filter needed final ArrayList<KeyRange> ranges = new ArrayList<>(jclasses.size()); for (JClass<?> jclass : jclasses) ranges.add(ObjId.getKeyRange(jclass.storageId)); array[i] = new KeyRanges(ranges); } this.pathKeyRanges = array; } return this.pathKeyRanges; }
private static CompositeIndexInfo findCompositeIndex(Permazen jdb, Class<?> startType, String indexName, int numValues) { CompositeIndexInfo indexInfo = null; for (JClass<?> jclass : jdb.getJClasses(startType)) { final JCompositeIndex index = jclass.jcompositeIndexesByName.get(indexName); if (index != null) { final CompositeIndexInfo candidate = jdb.getIndexInfo(index.storageId, CompositeIndexInfo.class); if (indexInfo != null && !candidate.equals(indexInfo)) { throw new IllegalArgumentException("ambiguous composite index name `" + indexName + "': multiple incompatible composite indexes with that name exist on sub-types of " + startType.getName()); } indexInfo = candidate; } } if (indexInfo == null) { throw new IllegalArgumentException("no composite index named `" + indexName + "' exists on any sub-type of " + startType.getName()); } if (numValues != indexInfo.getFieldTypes().size()) { throw new IllegalArgumentException("composite index `" + indexName + "' on " + startType.getName() + " has " + indexInfo.getFieldTypes().size() + " fields, not " + numValues); } return indexInfo; }
/** * Generate the {@link KeyRanges} restricting objects to the specified type. * * @param type any Java type, or null for no restriction * @return key restriction for {@code type} */ KeyRanges keyRangesFor(Class<?> type) { if (type == null) return KeyRanges.full(); final ArrayList<KeyRange> list = new ArrayList<>(this.jclasses.size()); boolean invert = false; if (type == UntypedJObject.class) { type = null; invert = true; } this.getJClasses(type).stream() .map(jclass -> ObjId.getKeyRange(jclass.storageId)) .forEach(list::add); final KeyRanges keyRanges = new KeyRanges(list); return invert ? keyRanges.inverse() : keyRanges; }
@Override ReferenceSchemaField toSchemaItem(Permazen jdb) { final ReferenceSchemaField schemaField = new ReferenceSchemaField(); super.initialize(jdb, schemaField); schemaField.setOnDelete(this.onDelete); schemaField.setCascadeDelete(this.cascadeDelete); schemaField.setAllowDeleted(this.allowDeleted); schemaField.setAllowDeletedSnapshot(this.allowDeletedSnapshot); final Class<?> rawType = this.typeToken.getRawType(); if (!rawType.isAssignableFrom(JObject.class)) { assert !rawType.isAssignableFrom(UntypedJObject.class); if (UntypedJObject.class.isAssignableFrom(rawType)) throw new RuntimeException("internal error: " + rawType); schemaField.setObjectTypes( jdb.getJClasses(rawType).stream() .map(jclass -> jclass.storageId) .collect(Collectors.toCollection(TreeSet::new))); } return schemaField; }
if (this.log.isTraceEnabled()) { this.log.trace("RefPath.stepThroughReference(): targetType=" + targetType + " -> " + ReferencePath.this.jdb.getJClasses(targetType)); for (JClass<?> targetJClass : ReferencePath.this.jdb.getJClasses(targetType)) { final ArrayList<Class<?>> newPathTypes = ReferencePath.copyAndAppend(this.pathTypes, targetJClass.getType()); newCursors.add(new Cursor(newReferenceFields, newPathTypes, targetJClass, null, this.fieldNames, false));
private SortKeyContainer(Permazen jdb, JClass<?> jclass, Class<?> type) { super(SortKey.class); this.jdb = jdb; this.jclass = jclass; this.type = type; // Add sort keys common to all objects final ArrayList<SortKey> sortKeys = new ArrayList<>(); sortKeys.add(new ObjectIdSortKey()); sortKeys.add(new VersionSortKey()); // Identify fields common to all sub-types of `type' SortedMap<Integer, JField> commonFields = Util.getCommonJFields(this.jdb.getJClasses(this.type)); // Add sort keys for all indexed fields common to all sub-types if (commonFields != null) { for (JField jfield : commonFields.values()) { if (jfield instanceof JComplexField) { ((JComplexField)jfield).getSubFields().stream() .filter(subField -> subField.isIndexed()) .map(FieldSortKey::new) .forEach(sortKeys::add); } else if (jfield instanceof JSimpleField && ((JSimpleField)jfield).isIndexed()) sortKeys.add(new FieldSortKey((JSimpleField)jfield)); } } // Sort indexed field sort keys Collections.sort(sortKeys.subList(2, sortKeys.size()), Comparator.comparing(SortKey::getDescription)); // Load container this.load(sortKeys); }
@Override public Void caseJReferenceField(JReferenceField field) { // Do forward cascades for (String cascadeName : field.forwardCascades) { if (cascadeName == null) continue; jclass.forwardCascadeMap.computeIfAbsent(cascadeName, s -> new ArrayList<>()).add(field); } // Do inverse cascades for (String cascadeName : field.inverseCascades) { if (cascadeName == null) continue; for (JClass<?> targetClass : Permazen.this.getJClasses(field.typeToken.getRawType())) { targetClass.inverseCascadeMap .computeIfAbsent(cascadeName, s -> new HashMap<>()) .computeIfAbsent(field.storageId, i -> new KeyRanges()) .add(ObjId.getKeyRange(jclass.storageId)); } } return null; }
List<? extends JClass<?>> jclasses = ReferencePath.this.jdb.getJClasses(type); if (type.isAssignableFrom(UntypedJObject.class)) { final ArrayList<JClass<?>> jclasses2 = new ArrayList<>(jclasses.size() + 1);
for (JClass<?> jclass : this.jdb.getJClasses().values()) { if (this.rootType.isAssignableFrom(jclass.getType())) { nodes.add(new Node(jclass));
final List<? extends JClass<?>> startJClasses = this.jdb.getJClasses(this.startType); if (startJClasses.isEmpty()) { throw new IllegalArgumentException(errorPrefix
private Collection<PropertyDef<?>> buildPropertyDefs() { final PropertyDefHolder pdefs = new PropertyDefHolder(); // Add properties shared by all JObjects pdefs.setPropertyDef(this.refLabelPropertyDef); pdefs.setPropertyDef(this.objIdPropertyDef); pdefs.setPropertyDef(this.objTypePropertyDef); pdefs.setPropertyDef(this.objVersionPropertyDef); // Add properties for all fields common to all sub-types of our configured type final SortedMap<Integer, JField> jfields = Util.getCommonJFields(this.jdb.getJClasses(this.type)); if (jfields != null) { for (JField jfield : jfields.values()) pdefs.setPropertyDef(new ObjFieldPropertyDef(jfield.getStorageId(), jfield.getName())); } // Apply any @ProvidesProperty-annotated method properties, possibly overridding jfields if (this.propertyScanner != null) { for (PropertyDef<?> propertyDef : this.propertyScanner.getPropertyDefs()) pdefs.setPropertyDef(propertyDef); } // Done return pdefs.values(); }