blob: 6a67b250a340a691b771370f78eb9e3eae0ced97 [file] [log] [blame]
/**
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.atlas.catalog.definition;
import org.apache.atlas.AtlasException;
import org.apache.atlas.catalog.*;
import org.apache.atlas.catalog.exception.CatalogRuntimeException;
import org.apache.atlas.catalog.exception.InvalidPayloadException;
import org.apache.atlas.catalog.projection.Projection;
import org.apache.atlas.catalog.projection.Relation;
import org.apache.atlas.typesystem.types.AttributeDefinition;
import org.apache.atlas.typesystem.types.AttributeInfo;
import org.apache.atlas.typesystem.types.Multiplicity;
import org.apache.atlas.typesystem.types.TypeSystem;
import java.util.*;
/**
* Base class for resource definitions.
*/
public abstract class BaseResourceDefinition implements ResourceDefinition {
protected static final TypeSystem typeSystem = TypeSystem.getInstance();
protected final Set<String> instanceProperties = new HashSet<>();
protected final Set<String> collectionProperties = new HashSet<>();
protected Map<String, AttributeDefinition> propertyDefs = new HashMap<>();
protected Map<String, AttributeInfo> properties = new HashMap<>();
protected final Map<String, Projection> projections = new HashMap<>();
protected final Map<String, Relation> relations = new HashMap<>();
protected final PropertyMapper propertyMapper;
protected final Map<String, PropertyValueFormatter> propertyValueFormatters = new HashMap<>();
public BaseResourceDefinition() {
DefaultDateFormatter defaultDateFormatter = new DefaultDateFormatter();
registerPropertyValueFormatter("creation_time", defaultDateFormatter);
registerPropertyValueFormatter("modified_time", defaultDateFormatter);
this.propertyMapper = createPropertyMapper();
}
@Override
public void validateCreatePayload(Request request) throws InvalidPayloadException {
Collection<String> propKeys = new HashSet<>(request.getQueryProperties().keySet());
Collection<String> missingProperties = new HashSet<>();
for (AttributeInfo property : properties.values()) {
String name = property.name;
if (property.multiplicity == Multiplicity.REQUIRED) {
if (request.getProperty(name) == null) {
missingProperties.add(name);
}
}
propKeys.remove(name);
}
if (! missingProperties.isEmpty() || ! propKeys.isEmpty()) {
throw new InvalidPayloadException(missingProperties, propKeys);
}
//todo: property type validation
}
@Override
public void validateUpdatePayload(Request request) throws InvalidPayloadException {
Collection<String> updateKeys = new HashSet<>(request.getUpdateProperties().keySet());
Collection<String> validProperties = new HashSet<>(properties.keySet());
// currently updating 'name' property for any resource is unsupported
validProperties.remove("name");
updateKeys.removeAll(validProperties);
if (! updateKeys.isEmpty()) {
throw new InvalidPayloadException(Collections.<String>emptySet(), updateKeys);
}
}
@Override
public Collection<AttributeDefinition> getPropertyDefinitions() {
return propertyDefs.values();
}
@Override
public Map<String, Object> filterProperties(Request request, Map<String, Object> propertyMap) {
Request.Cardinality cardinality = request.getCardinality();
Collection<String> requestProperties = request.getAdditionalSelectProperties();
Iterator<Map.Entry<String, Object>> propIter = propertyMap.entrySet().iterator();
while(propIter.hasNext()) {
Map.Entry<String, Object> propEntry = propIter.next();
String prop = propEntry.getKey();
if (! requestProperties.contains(prop)) {
if (cardinality == Request.Cardinality.COLLECTION) {
if (! collectionProperties.contains(prop)) {
propIter.remove();
}
} else {
if (! instanceProperties.isEmpty() && ! instanceProperties.contains(prop)) {
propIter.remove();
}
}
}
}
return propertyMap;
}
@Override
public Map<String, Projection> getProjections() {
return projections;
}
@Override
public Map<String, Relation> getRelations() {
return relations;
}
@Override
public synchronized PropertyMapper getPropertyMapper() {
return propertyMapper;
}
@Override
public Map<String, PropertyValueFormatter> getPropertyValueFormatters() {
return propertyValueFormatters;
}
protected void registerProperty(AttributeDefinition propertyDefinition) {
try {
propertyDefs.put(propertyDefinition.name, propertyDefinition);
properties.put(propertyDefinition.name, new AttributeInfo(typeSystem, propertyDefinition, null));
} catch (AtlasException e) {
throw new CatalogRuntimeException("Unable to create attribute: " + propertyDefinition.name, e);
}
}
protected void registerPropertyValueFormatter(String property, PropertyValueFormatter valueFormatter) {
propertyValueFormatters.put(property, valueFormatter);
}
/**
* Create a new property mapper instance.
* Should be overridden in children where the default implementation isn't sufficient.
*
* @return a new property mapper instance
*/
protected PropertyMapper createPropertyMapper() {
return new DefaultPropertyMapper();
}
}