package org.vertexium; import com.google.common.collect.ImmutableSet; import org.vertexium.mutation.ElementMutation; import org.vertexium.mutation.ExistingElementMutation; import org.vertexium.mutation.PropertyDeleteMutation; import org.vertexium.mutation.PropertySoftDeleteMutation; import org.vertexium.property.MutableProperty; import org.vertexium.property.MutablePropertyImpl; import org.vertexium.property.PropertyValue; import org.vertexium.util.ConvertingIterable; import org.vertexium.util.FilterIterable; import org.vertexium.util.PropertyCollection; import java.util.*; import java.util.concurrent.ConcurrentSkipListSet; public abstract class ElementBase implements Element { private final Graph graph; private final String id; private Property idProperty; private Property edgeLabelProperty; private Visibility visibility; private final long timestamp; private final EnumSet<FetchHint> fetchHints; private Set<Visibility> hiddenVisibilities = new HashSet<>(); private final PropertyCollection properties; private final ImmutableSet<String> extendedDataTableNames; private ConcurrentSkipListSet<PropertyDeleteMutation> propertyDeleteMutations; private ConcurrentSkipListSet<PropertySoftDeleteMutation> propertySoftDeleteMutations; private final Authorizations authorizations; protected ElementBase( Graph graph, String id, Visibility visibility, Iterable<Property> properties, Iterable<PropertyDeleteMutation> propertyDeleteMutations, Iterable<PropertySoftDeleteMutation> propertySoftDeleteMutations, Iterable<Visibility> hiddenVisibilities, ImmutableSet<String> extendedDataTableNames, long timestamp, EnumSet<FetchHint> fetchHints, Authorizations authorizations ) { this.graph = graph; this.id = id; this.visibility = visibility; this.timestamp = timestamp; this.fetchHints = fetchHints; this.properties = new PropertyCollection(); this.extendedDataTableNames = extendedDataTableNames; this.authorizations = authorizations; if (hiddenVisibilities != null) { for (Visibility v : hiddenVisibilities) { this.hiddenVisibilities.add(v); } } updatePropertiesInternal(properties, propertyDeleteMutations, propertySoftDeleteMutations); } @Override public Iterable<Object> getPropertyValues(final String name) { return new ConvertingIterable<Property, Object>(getProperties(name)) { @Override protected Object convert(Property p) { return p.getValue(); } }; } @Override public Iterable<Object> getPropertyValues(String key, String name) { return new ConvertingIterable<Property, Object>(getProperties(key, name)) { @Override protected Object convert(Property p) { return p.getValue(); } }; } @Override public Property getProperty(String name, Visibility visibility) { return getProperty(ElementMutation.DEFAULT_KEY, name, visibility); } @Override public Property getProperty(String key, String name, Visibility visibility) { if (ID_PROPERTY_NAME.equals(name)) { return getIdProperty(); } else if (Edge.LABEL_PROPERTY_NAME.equals(name) && this instanceof Edge) { return getEdgeLabelProperty(); } for (Property p : getProperties(name)) { if (!p.getKey().equals(key)) { continue; } if (visibility == null) { return p; } if (!visibility.equals(p.getVisibility())) { continue; } return p; } return null; } @Override public Property getProperty(String key, String name) { return getProperty(key, name, null); } @Override public Property getProperty(String name) { if (ID_PROPERTY_NAME.equals(name)) { return getIdProperty(); } else if (Edge.LABEL_PROPERTY_NAME.equals(name) && this instanceof Edge) { return getEdgeLabelProperty(); } Iterator<Property> propertiesWithName = getProperties(name).iterator(); if (propertiesWithName.hasNext()) { return propertiesWithName.next(); } return null; } @Override public Object getPropertyValue(String name) { return getPropertyValue(name, 0); } @Override public Object getPropertyValue(String name, int index) { if (ID_PROPERTY_NAME.equals(name)) { return getIdProperty(); } else if (Edge.LABEL_PROPERTY_NAME.equals(name) && this instanceof Edge) { return getEdgeLabelProperty(); } Property property = this.properties.getProperty(name, index); if (property == null) { return null; } return property.getValue(); } @Override public Object getPropertyValue(String key, String name, int index) { if (ID_PROPERTY_NAME.equals(name)) { return getIdProperty(); } else if (Edge.LABEL_PROPERTY_NAME.equals(name) && this instanceof Edge) { return getEdgeLabelProperty(); } Property property = this.properties.getProperty(key, name, index); if (property == null) { return null; } return property.getValue(); } @Override public Object getPropertyValue(String key, String name) { return getPropertyValue(key, name, 0); } @Override public String getId() { return this.id; } protected Property getIdProperty() { if (idProperty == null) { idProperty = new MutablePropertyImpl( ElementMutation.DEFAULT_KEY, ID_PROPERTY_NAME, getId(), null, getTimestamp(), null, null, getFetchHints() ); } return idProperty; } protected Property getEdgeLabelProperty() { if (edgeLabelProperty == null && this instanceof Edge) { String edgeLabel = ((Edge) this).getLabel(); edgeLabelProperty = new MutablePropertyImpl( ElementMutation.DEFAULT_KEY, Edge.LABEL_PROPERTY_NAME, edgeLabel, null, getTimestamp(), null, null, getFetchHints() ); } return edgeLabelProperty; } @Override public Visibility getVisibility() { return this.visibility; } @Override public long getTimestamp() { return timestamp; } protected void setVisibility(Visibility visibility) { this.visibility = visibility; } @Override public Iterable<Property> getProperties() { return this.properties.getProperties(); } public Iterable<PropertyDeleteMutation> getPropertyDeleteMutations() { return this.propertyDeleteMutations; } public Iterable<PropertySoftDeleteMutation> getPropertySoftDeleteMutations() { return this.propertySoftDeleteMutations; } @Override public Iterable<Property> getProperties(String name) { if (ID_PROPERTY_NAME.equals(name)) { ArrayList<Property> result = new ArrayList<>(); result.add(getIdProperty()); return result; } else if (Edge.LABEL_PROPERTY_NAME.equals(name) && this instanceof Edge) { ArrayList<Property> result = new ArrayList<>(); result.add(getEdgeLabelProperty()); return result; } return this.properties.getProperties(name); } @Override public Iterable<Property> getProperties(final String key, final String name) { if (ID_PROPERTY_NAME.equals(name) || (Edge.LABEL_PROPERTY_NAME.equals(name) && this instanceof Edge)) { return getProperties(name); } return this.properties.getProperties(key, name); } // this method differs setProperties in that it only updates the in memory representation of the properties protected void updatePropertiesInternal( Iterable<Property> properties, Iterable<PropertyDeleteMutation> propertyDeleteMutations, Iterable<PropertySoftDeleteMutation> propertySoftDeleteMutations ) { if (propertyDeleteMutations != null) { this.propertyDeleteMutations = new ConcurrentSkipListSet<>(); for (PropertyDeleteMutation propertyDeleteMutation : propertyDeleteMutations) { removePropertyInternal( propertyDeleteMutation.getKey(), propertyDeleteMutation.getName(), propertyDeleteMutation.getVisibility() ); this.propertyDeleteMutations.add(propertyDeleteMutation); } } if (propertySoftDeleteMutations != null) { this.propertySoftDeleteMutations = new ConcurrentSkipListSet<>(); for (PropertySoftDeleteMutation propertySoftDeleteMutation : propertySoftDeleteMutations) { removePropertyInternal( propertySoftDeleteMutation.getKey(), propertySoftDeleteMutation.getName(), propertySoftDeleteMutation.getVisibility() ); this.propertySoftDeleteMutations.add(propertySoftDeleteMutation); } } for (Property property : properties) { addPropertyInternal(property); } } protected void addPropertyInternal(Property property) { if (property.getKey() == null) { throw new IllegalArgumentException("key is required for property"); } Object propertyValue = property.getValue(); if (propertyValue instanceof PropertyValue && !((PropertyValue) propertyValue).isStore()) { return; } Property existingProperty = getProperty(property.getKey(), property.getName(), property.getVisibility()); if (existingProperty == null) { this.properties.addProperty(property); } else { if (existingProperty instanceof MutableProperty) { ((MutableProperty) existingProperty).update(property); } else { throw new VertexiumException("Could not update property of type: " + existingProperty.getClass().getName()); } } } protected Property removePropertyInternal(String key, String name, Visibility visibility) { Property property = getProperty(key, name, visibility); if (property != null) { this.properties.removeProperty(property); } return property; } protected Property removePropertyInternal(String key, String name) { Property property = getProperty(key, name); if (property != null) { this.properties.removeProperty(property); } return property; } protected Property softDeletePropertyInternal(String key, String name) { Property property = getProperty(key, name); if (property != null) { this.properties.removeProperty(property); } return property; } protected Property softDeletePropertyInternal(String key, String name, Visibility visibility) { Property property = getProperty(key, name, visibility); if (property != null) { this.properties.removeProperty(property); } return property; } protected Iterable<Property> removePropertyInternal(String name) { return this.properties.removeProperties(name); } public Graph getGraph() { return graph; } @Override public int hashCode() { return getId().hashCode(); } @Override public String toString() { if (this instanceof Edge) { Edge edge = (Edge) this; return getId() + ":[" + edge.getVertexId(Direction.OUT) + "-" + edge.getLabel() + "->" + edge.getVertexId(Direction.IN) + "]"; } return getId(); } @Override public boolean equals(Object obj) { if (obj instanceof Element) { Element objElem = (Element) obj; return getId().equals(objElem.getId()); } return super.equals(obj); } @Override public abstract void deleteProperty(String key, String name, Authorizations authorizations); @Override public abstract void deleteProperties(String name, Authorizations authorizations); @Override public abstract void softDeleteProperty(String key, String name, Authorizations authorizations); @Override public abstract void softDeleteProperty(String key, String name, Visibility visibility, Authorizations authorizations); @Override public abstract void softDeleteProperties(String name, Authorizations authorizations); @Override public void addPropertyValue(String key, String name, Object value, Visibility visibility, Authorizations authorizations) { prepareMutation().addPropertyValue(key, name, value, visibility).save(authorizations); } @Override public void addPropertyValue(String key, String name, Object value, Metadata metadata, Visibility visibility, Authorizations authorizations) { prepareMutation().addPropertyValue(key, name, value, metadata, visibility).save(authorizations); } @Override public void setProperty(String name, Object value, Visibility visibility, Authorizations authorizations) { prepareMutation().setProperty(name, value, visibility).save(authorizations); } @Override public void setProperty(String name, Object value, Metadata metadata, Visibility visibility, Authorizations authorizations) { prepareMutation().setProperty(name, value, metadata, visibility).save(authorizations); } @Override public void markPropertyHidden(String key, String name, Visibility propertyVisibility, Long timestamp, Visibility visibility, Authorizations authorizations) { Iterable<Property> properties = getProperties(key, name); for (Property property : properties) { if (property.getVisibility().equals(propertyVisibility)) { markPropertyHidden(property, timestamp, visibility, authorizations); return; } } throw new IllegalArgumentException("Could not find property " + key + " : " + name + " : " + propertyVisibility); } @Override public void markPropertyHidden(String key, String name, Visibility propertyVisibility, Visibility visibility, Authorizations authorizations) { markPropertyHidden(key, name, propertyVisibility, null, visibility, authorizations); } @Override public void markPropertyHidden(Property property, Visibility visibility, Authorizations authorizations) { markPropertyHidden(property, null, visibility, authorizations); } @Override public void markPropertyVisible(String key, String name, Visibility propertyVisibility, Long timestamp, Visibility visibility, Authorizations authorizations) { Iterable<Property> properties = getProperties(key, name); for (Property property : properties) { if (property.getVisibility().equals(propertyVisibility)) { markPropertyVisible(property, timestamp, visibility, authorizations); return; } } throw new IllegalArgumentException("Could not find property " + key + " : " + name + " : " + propertyVisibility); } @Override public void markPropertyVisible(String key, String name, Visibility propertyVisibility, Visibility visibility, Authorizations authorizations) { markPropertyVisible(key, name, propertyVisibility, null, visibility, authorizations); } @Override public void markPropertyVisible(Property property, Visibility visibility, Authorizations authorizations) { markPropertyVisible(property, null, visibility, authorizations); } @Override public abstract <T extends Element> ExistingElementMutation<T> prepareMutation(); @Override public abstract void markPropertyHidden(Property property, Long timestamp, Visibility visibility, Authorizations authorizations); @Override public abstract void markPropertyVisible(Property property, Long timestamp, Visibility visibility, Authorizations authorizations); @Override public Authorizations getAuthorizations() { return authorizations; } @Override public void mergeProperties(Element element) { for (Property property : element.getProperties()) { this.properties.removeProperty(property); this.properties.addProperty(property); } } public Iterable<Visibility> getHiddenVisibilities() { return hiddenVisibilities; } @Override public boolean isHidden(Authorizations authorizations) { for (Visibility visibility : getHiddenVisibilities()) { if (authorizations.canRead(visibility)) { return true; } } return false; } @Override public abstract void deleteProperty(String key, String name, Visibility visibility, Authorizations authorizations); @Override public Iterable<HistoricalPropertyValue> getHistoricalPropertyValues(Long startTime, Long endTime, Authorizations authorizations) { return getHistoricalPropertyValues(null, null, null, startTime, endTime, authorizations); } @Override public Iterable<HistoricalPropertyValue> getHistoricalPropertyValues(Authorizations authorizations) { return getHistoricalPropertyValues(null, null, authorizations); } @Override public Iterable<HistoricalPropertyValue> getHistoricalPropertyValues(String key, String name, Visibility visibility, Authorizations authorizations) { return getHistoricalPropertyValues(key, name, visibility, null, null, authorizations); } @Override public Iterable<HistoricalPropertyValue> getHistoricalPropertyValues(String key, String name, Visibility visibility, final Long startTime, final Long endTime, Authorizations authorizations) { return new FilterIterable<HistoricalPropertyValue>(getHistoricalPropertyValues(key, name, visibility, authorizations)) { @Override protected boolean isIncluded(HistoricalPropertyValue pv) { if (startTime != null && pv.getTimestamp() < startTime) { return false; } if (endTime != null && pv.getTimestamp() > endTime) { return false; } return true; } }; } @Override public ImmutableSet<String> getExtendedDataTableNames() { return extendedDataTableNames; } @Override public EnumSet<FetchHint> getFetchHints() { return fetchHints; } }