| /* |
| * 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.builders |
| |
| import org.apache.atlas.typesystem.{IReferenceableInstance, IStruct, Referenceable, Struct} |
| |
| import scala.collection.JavaConversions._ |
| import scala.collection.JavaConverters._ |
| import scala.collection.mutable.ArrayBuffer |
| import scala.language.{dynamics, implicitConversions} |
| import scala.util.DynamicVariable |
| |
| class InstanceBuilder extends Dynamic { |
| |
| private val references : ArrayBuffer[Referenceable] = new ArrayBuffer[Referenceable]() |
| |
| val context = new DynamicVariable[DynamicStruct](null) |
| |
| def struct(typeName : String) : DynamicStruct = { |
| context.value = new DynamicStruct(this, new Struct(typeName)) |
| context.value |
| } |
| |
| def instance(typeName: String, traitNames: String*)(f : => Unit) : DynamicReference = { |
| val r = new Referenceable(typeName, traitNames:_*) |
| references.append(r) |
| val dr = new DynamicReference(this, r) |
| context.withValue(dr){f} |
| dr |
| } |
| |
| def create( f : => Unit ) : java.util.List[Referenceable] = { |
| f |
| references.asJava |
| } |
| |
| def applyDynamic(name : String)(value : Any) : Any = { |
| context.value.updateDynamic(name)(value) |
| } |
| |
| implicit def symbolToDynamicStruct(s : Symbol) : DynamicValue = |
| new DynamicValue(this, s.name, if (context.value == null) null else context.value.s) |
| |
| } |
| |
| object DynamicValue { |
| |
| private[builders] def transformOut(s: IStruct, attr : String, v : Any)(implicit ib : InstanceBuilder) : DynamicValue = |
| v match { |
| case r : Referenceable => new DynamicReference(ib, r) |
| case s : Struct => new DynamicStruct(ib, s) |
| case jL : java.util.List[_] => { |
| if ( s != null ) { |
| new DynamicCollection(ib, attr, s) |
| } else { |
| new DynamicValue(ib, attr, s, jL.map { e => transformOut(null, null, e) }) |
| } |
| } |
| case jM : java.util.Map[_,_] => { |
| if ( s != null ) { |
| new DynamicMap(ib, attr, s) |
| } else { |
| new DynamicValue(ib, attr, s, jM.map { |
| case (k, v) => k -> transformOut(null, null, v) |
| }.toMap) |
| } |
| } |
| case x => { |
| if ( s != null ) { |
| new DynamicValue(ib, attr, s) |
| } else { |
| new DynamicValue(ib, attr, s, x) |
| } |
| } |
| } |
| |
| private[builders] def transformIn(v : Any) : Any = v match { |
| case dr : DynamicReference => dr.r |
| case ds : DynamicStruct => ds.s |
| case dv : DynamicValue => dv.get |
| case l : Seq[_] => l.map{ e => transformIn(e)}.asJava |
| case m : Map[_,_] => m.map { |
| case (k,v) => k -> transformIn(v) |
| }.asJava |
| case x => x |
| } |
| |
| } |
| |
| class DynamicValue(val ib : InstanceBuilder, val attrName : String, val s: IStruct, var value : Any = null) extends Dynamic { |
| import DynamicValue._ |
| |
| implicit val iib : InstanceBuilder = ib |
| |
| def ~(v : Any): Unit = { |
| if ( s != null ) { |
| s.set(attrName, transformIn(v)) |
| } else { |
| value = v |
| } |
| } |
| |
| def get : Any = if ( s != null ) s.get(attrName) else value |
| |
| def selectDynamic(name: String) : DynamicValue = { |
| |
| throw new UnsupportedOperationException() |
| } |
| |
| def update(key : Any, value : Object): Unit = { |
| throw new UnsupportedOperationException() |
| } |
| |
| def apply(key : Any): DynamicValue = { |
| |
| if ( s != null && s.isInstanceOf[Referenceable] && key.isInstanceOf[String]) { |
| val r = s.asInstanceOf[Referenceable] |
| if ( r.getTraits contains attrName ) { |
| val traitAttr = key.asInstanceOf[String] |
| return new DynamicStruct(ib, r.getTrait(attrName)).selectDynamic(traitAttr) |
| } |
| } |
| throw new UnsupportedOperationException() |
| } |
| } |
| |
| class DynamicCollection(ib : InstanceBuilder, attrName : String, s: IStruct) extends DynamicValue(ib, attrName ,s) { |
| import DynamicValue._ |
| |
| override def update(key : Any, value : Object): Unit = { |
| var jL = s.get(attrName) |
| val idx = key.asInstanceOf[Int] |
| if (jL == null ) { |
| val l = new java.util.ArrayList[Object]() |
| l.ensureCapacity(idx) |
| jL = l |
| } |
| val nJL = new java.util.ArrayList[Object](jL.asInstanceOf[java.util.List[Object]]) |
| nJL.asInstanceOf[java.util.List[Object]].set(idx, transformIn(value).asInstanceOf[Object]) |
| s.set(attrName, nJL) |
| } |
| |
| override def apply(key : Any): DynamicValue = { |
| var jL = s.get(attrName) |
| val idx = key.asInstanceOf[Int] |
| if (jL == null ) { |
| null |
| } else { |
| transformOut(null, null, jL.asInstanceOf[java.util.List[Object]].get(idx)) |
| } |
| } |
| } |
| |
| class DynamicMap(ib : InstanceBuilder, attrName : String, s: IStruct) extends DynamicValue(ib, attrName ,s) { |
| import DynamicValue._ |
| override def update(key : Any, value : Object): Unit = { |
| var jM = s.get(attrName) |
| if (jM == null ) { |
| jM = new java.util.HashMap[Object, Object]() |
| } |
| jM.asInstanceOf[java.util.Map[Object, Object]].put(key.asInstanceOf[AnyRef], value) |
| } |
| |
| override def apply(key : Any): DynamicValue = { |
| var jM = s.get(attrName) |
| if (jM == null ) { |
| null |
| } else { |
| transformOut(null, null, jM.asInstanceOf[java.util.Map[Object, Object]].get(key)) |
| } |
| } |
| } |
| |
| class DynamicStruct(ib : InstanceBuilder, s: IStruct) extends DynamicValue(ib, null ,s) { |
| import DynamicValue._ |
| override def selectDynamic(name: String) : DynamicValue = { |
| transformOut(s, name, s.get(name)) |
| } |
| |
| def updateDynamic(name: String)(value: Any) { |
| s.set(name, transformIn(value)) |
| } |
| |
| override def ~(v : Any): Unit = { throw new UnsupportedOperationException()} |
| override def get : Any = s |
| |
| } |
| |
| class DynamicReference(ib : InstanceBuilder, val r : IReferenceableInstance) extends DynamicStruct(ib, r) { |
| |
| private def _trait(name : String) = new DynamicStruct(ib, r.getTrait(name)) |
| |
| override def selectDynamic(name: String) : DynamicValue = { |
| if ( r.getTraits contains name ) { |
| _trait(name) |
| } else { |
| super.selectDynamic(name) |
| } |
| } |
| |
| } |