| /** |
| * 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.atlas.typesystem.types; |
| |
| import com.google.common.collect.ImmutableBiMap; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSet; |
| |
| import org.apache.atlas.AtlasConstants; |
| import org.apache.atlas.AtlasException; |
| import org.apache.atlas.typesystem.IReferenceableInstance; |
| import org.apache.atlas.typesystem.IStruct; |
| import org.apache.atlas.typesystem.ITypedReferenceableInstance; |
| import org.apache.atlas.typesystem.ITypedStruct; |
| import org.apache.atlas.typesystem.Referenceable; |
| import org.apache.atlas.typesystem.Struct; |
| import org.apache.atlas.typesystem.persistence.AtlasSystemAttributes; |
| import org.apache.atlas.typesystem.persistence.Id; |
| import org.apache.atlas.typesystem.persistence.ReferenceableInstance; |
| import org.apache.atlas.typesystem.persistence.StructInstance; |
| import scala.tools.cmd.gen.AnyVals; |
| |
| import java.math.BigDecimal; |
| import java.math.BigInteger; |
| import java.nio.charset.Charset; |
| import java.security.MessageDigest; |
| import java.util.*; |
| |
| public class ClassType extends HierarchicalType<ClassType, IReferenceableInstance> |
| implements IConstructableType<IReferenceableInstance, ITypedReferenceableInstance> { |
| |
| public static final String TRAIT_NAME_SEP = "::"; |
| |
| public final Map<AttributeInfo, List<String>> infoToNameMap; |
| |
| ClassType(TypeSystem typeSystem, String name, String description, ImmutableSet<String> superTypes, int numFields) { |
| this(typeSystem, name, description, AtlasConstants.DEFAULT_TYPE_VERSION, superTypes, numFields); |
| } |
| |
| ClassType(TypeSystem typeSystem, String name, String description, String version, ImmutableSet<String> superTypes, int numFields) { |
| super(typeSystem, ClassType.class, name, description, version, superTypes, numFields); |
| infoToNameMap = null; |
| } |
| |
| ClassType(TypeSystem typeSystem, String name, String description, ImmutableSet<String> superTypes, AttributeInfo... fields) |
| throws AtlasException { |
| this(typeSystem, name, description, AtlasConstants.DEFAULT_TYPE_VERSION, superTypes, fields); |
| } |
| |
| ClassType(TypeSystem typeSystem, String name, String description, String version, ImmutableSet<String> superTypes, AttributeInfo... fields) |
| throws AtlasException { |
| super(typeSystem, ClassType.class, name, description, version, superTypes, fields); |
| infoToNameMap = TypeUtils.buildAttrInfoToNameMap(fieldMapping); |
| } |
| |
| @Override |
| public DataTypes.TypeCategory getTypeCategory() { |
| return DataTypes.TypeCategory.CLASS; |
| } |
| |
| public void validateId(Id id) throws AtlasException { |
| if (id != null) { |
| ClassType cType = typeSystem.getDataType(ClassType.class, id.typeName); |
| if (isSubType(cType.getName())) { |
| return; |
| } |
| throw new AtlasException(String.format("Id %s is not valid for class %s", id, getName())); |
| } |
| } |
| |
| protected Id getId(Object val) throws AtlasException { |
| if (val instanceof Referenceable) { |
| return ((Referenceable) val).getId(); |
| } |
| throw new AtlasException(String.format("Cannot get id from class %s", val.getClass())); |
| } |
| |
| @Override |
| public ITypedReferenceableInstance convert(Object val, Multiplicity m) throws AtlasException { |
| |
| if (val != null) { |
| if (val instanceof ITypedReferenceableInstance) { |
| ITypedReferenceableInstance tr = (ITypedReferenceableInstance) val; |
| if (!tr.getTypeName().equals(getName())) { |
| /* |
| * If val is a subType instance; invoke convert on it. |
| */ |
| ClassType valType = typeSystem.getDataType(superTypeClass, tr.getTypeName()); |
| if (valType.superTypePaths.containsKey(name)) { |
| return valType.convert(val, m); |
| } |
| throw new ValueConversionException(this, val); |
| } |
| return tr; |
| } else if (val instanceof Struct) { |
| Struct s = (Struct) val; |
| Referenceable r = null; |
| Id id = null; |
| |
| if (!s.typeName.equals(getName())) { |
| /* |
| * If val is a subType instance; invoke convert on it. |
| */ |
| ClassType valType = typeSystem.getDataType(superTypeClass, s.typeName); |
| if (valType.superTypePaths.containsKey(name)) { |
| return valType.convert(s, m); |
| } |
| throw new ValueConversionException(this, val); |
| } |
| |
| if (val instanceof Referenceable) { |
| r = (Referenceable) val; |
| id = r.getId(); |
| } |
| |
| ITypedReferenceableInstance tr = |
| r != null ? createInstanceWithTraits(id, null, r, r.getTraits().toArray(new String[0])) : |
| createInstance(id); |
| |
| if (id != null && id.isAssigned()) { |
| return tr; |
| } |
| |
| for (Map.Entry<String, AttributeInfo> e : fieldMapping.fields.entrySet()) { |
| String attrKey = e.getKey(); |
| AttributeInfo i = e.getValue(); |
| Object aVal = s.get(attrKey); |
| if (aVal != null && i.dataType().getTypeCategory() == DataTypes.TypeCategory.CLASS) { |
| if (!i.isComposite) { |
| aVal = ((IReferenceableInstance) aVal).getId(); |
| } |
| } |
| |
| if(!i.multiplicity.nullAllowed() && !s.getValuesMap().containsKey(attrKey)){ |
| throw new ValueConversionException.NullConversionException(i.multiplicity, |
| String.format(" Value expected for required attribute %s", i.name)); |
| } else { |
| try { |
| if (s.getValuesMap().containsKey(attrKey)) { |
| tr.set(attrKey, aVal); |
| } |
| } catch (ValueConversionException ve) { |
| throw new ValueConversionException(this, val, ve); |
| } |
| } |
| } |
| |
| return tr; |
| } else if (val instanceof ReferenceableInstance) { |
| validateId(((ReferenceableInstance) val).getId()); |
| return (ReferenceableInstance) val; |
| } else { |
| throw new ValueConversionException(this, val, "value's class is " + val.getClass().getName()); |
| } |
| } |
| if (!m.nullAllowed()) { |
| throw new ValueConversionException.NullConversionException(m); |
| } |
| return null; |
| } |
| |
| @Override |
| public ITypedReferenceableInstance createInstance() throws AtlasException { |
| return createInstance((String[]) null); |
| } |
| |
| public ITypedReferenceableInstance createInstance(String... traitNames) throws AtlasException { |
| return createInstance(null, traitNames); |
| } |
| |
| public ITypedReferenceableInstance createInstance(Id id, String... traitNames) throws AtlasException { |
| return createInstanceWithTraits(id, null, null, traitNames); |
| } |
| |
| public ITypedReferenceableInstance createInstance(Id id, AtlasSystemAttributes systemAttributes, String... traitNames) throws AtlasException{ |
| return createInstanceWithTraits(id, systemAttributes, null, traitNames); |
| } |
| |
| public ITypedReferenceableInstance createInstanceWithTraits(Id id, AtlasSystemAttributes systemAttributes, Referenceable r, String... traitNames) |
| throws AtlasException { |
| |
| ImmutableMap.Builder<String, ITypedStruct> b = new ImmutableBiMap.Builder<>(); |
| if (traitNames != null) { |
| for (String t : traitNames) { |
| TraitType tType = typeSystem.getDataType(TraitType.class, t); |
| IStruct iTraitObject = r == null ? null : r.getTrait(t); |
| ITypedStruct trait = iTraitObject == null ? tType.createInstance() : |
| tType.convert(iTraitObject, Multiplicity.REQUIRED); |
| b.put(t, trait); |
| } |
| } |
| |
| return new ReferenceableInstance(id == null ? new Id(getName()) : id, getName(), systemAttributes, fieldMapping, |
| new boolean[fieldMapping.fields.size()], new boolean[fieldMapping.fields.size()], |
| fieldMapping.numBools == 0 ? null : new boolean[fieldMapping.numBools], |
| fieldMapping.numBytes == 0 ? null : new byte[fieldMapping.numBytes], |
| fieldMapping.numShorts == 0 ? null : new short[fieldMapping.numShorts], |
| fieldMapping.numInts == 0 ? null : new int[fieldMapping.numInts], |
| fieldMapping.numLongs == 0 ? null : new long[fieldMapping.numLongs], |
| fieldMapping.numFloats == 0 ? null : new float[fieldMapping.numFloats], |
| fieldMapping.numDoubles == 0 ? null : new double[fieldMapping.numDoubles], |
| fieldMapping.numBigDecimals == 0 ? null : new BigDecimal[fieldMapping.numBigDecimals], |
| fieldMapping.numBigInts == 0 ? null : new BigInteger[fieldMapping.numBigInts], |
| fieldMapping.numDates == 0 ? null : new Date[fieldMapping.numDates], |
| fieldMapping.numStrings == 0 ? null : new String[fieldMapping.numStrings], |
| fieldMapping.numArrays == 0 ? null : new ImmutableList[fieldMapping.numArrays], |
| fieldMapping.numMaps == 0 ? null : new ImmutableMap[fieldMapping.numMaps], |
| fieldMapping.numStructs == 0 ? null : new StructInstance[fieldMapping.numStructs], |
| fieldMapping.numReferenceables == 0 ? null : new ReferenceableInstance[fieldMapping.numReferenceables], |
| fieldMapping.numReferenceables == 0 ? null : new Id[fieldMapping.numReferenceables], b.build()); |
| } |
| |
| @Override |
| public void output(IReferenceableInstance s, Appendable buf, String prefix, Set<IReferenceableInstance> inProcess) throws AtlasException { |
| fieldMapping.output(s, buf, prefix, inProcess); |
| } |
| |
| @Override |
| public List<String> getNames(AttributeInfo info) { |
| return infoToNameMap.get(info); |
| } |
| |
| @Override |
| public void updateSignatureHash(MessageDigest digester, Object val) throws AtlasException { |
| if( !(val instanceof ITypedReferenceableInstance)) { |
| throw new IllegalArgumentException("Unexpected value type " + val.getClass().getSimpleName() + ". Expected instance of ITypedStruct"); |
| } |
| digester.update(getName().getBytes(Charset.forName("UTF-8"))); |
| |
| if(fieldMapping.fields != null && val != null) { |
| IReferenceableInstance typedValue = (IReferenceableInstance) val; |
| if(fieldMapping.fields.values() != null) { |
| for (AttributeInfo aInfo : fieldMapping.fields.values()) { |
| Object attrVal = typedValue.get(aInfo.name); |
| if (attrVal != null) { |
| aInfo.dataType().updateSignatureHash(digester, attrVal); |
| } |
| } |
| } |
| } |
| } |
| } |