All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bndly.schema.model.SchemaBuilder Maven / Gradle / Ivy

The newest version!
package org.bndly.schema.model;

/*-
 * #%L
 * Schema Model
 * %%
 * Copyright (C) 2013 - 2020 Cybercon GmbH
 * %%
 * Licensed 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.
 * #L%
 */

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SchemaBuilder implements SchemaProvider {

	private final Schema schema;
	private final Map namedAttributeHoldersByName;
	private final Map typesByName;
	private final Map mixinsByName;
	private final List inverseAttributes;
	private NamedAttributeHolder currentAttributeHolder;
	private Type currentType;
	private Mixin currentMixin;
	private Attribute currentAttribute;

	public SchemaBuilder(String name, String namespace) {
		schema = new Schema(name, namespace);
		typesByName = new HashMap<>();
		mixinsByName = new HashMap<>();
		namedAttributeHoldersByName = new HashMap<>();
		inverseAttributes = new ArrayList<>();
	}

	@Override
	public String getSchemaName() {
		return schema.getName();
	}

	@Override
	public Schema getSchema() {
		for (InverseAttribute inverseAttribute : inverseAttributes) {
			Map atts = SchemaUtil.collectAttributesAsMap(inverseAttribute.getReferencedAttributeHolder());
			NamedAttributeHolderAttribute namedAttributeHolderAttribute = null;
			Attribute att = atts.get(inverseAttribute.getReferencedAttributeName());
			if (NamedAttributeHolderAttribute.class.isInstance(att)) {
				namedAttributeHolderAttribute = (NamedAttributeHolderAttribute) att;
			}
			if (namedAttributeHolderAttribute == null) {
				if (!inverseAttribute.isVirtual()) {
					throw new IllegalStateException("could not find referenced attribute for inverse attribute");
				}
			}
			inverseAttribute.setReferencedAttribute(namedAttributeHolderAttribute);
		}
		return schema;
	}

	public SchemaBuilder abstractType() {
		currentType.setAbstract(true);
		return this;
	}

	public SchemaBuilder abstractType(String name) {
		type(name);
		return abstractType();
	}

	public SchemaBuilder virtualType(String name) {
		Type type = assertTypeExists(name);
		type.setVirtual(true);
		currentType = type;
		currentAttributeHolder = type;
		return this;
	}

	public SchemaBuilder type(String name) {
		Type type = assertTypeExists(name);
		currentType = type;
		currentAttributeHolder = type;
		return this;
	}

	public SchemaBuilder parentType(String parentTypeName) {
		if (currentType != null) {
			Type superType = assertTypeExists(parentTypeName);
			currentType.setSuperType(superType);
			List subs = superType.getSubTypes();
			if (subs == null) {
				subs = new ArrayList<>();
				superType.setSubTypes(subs);
			}
			subs.add(currentType);
		}
		return this;
	}

	public SchemaBuilder annotateTypeOrMixin(String key, String value) {
		if (currentAttributeHolder != null) {
			currentAttributeHolder.annotate(key, value);
		}
		return this;
	}

	public SchemaBuilder annotateAttribute(String key, String value) {
		if (currentAttribute != null) {
			currentAttribute.annotate(key, value);
		}
		return this;
	}

	public SchemaBuilder annotateSchema(String key, String value) {
		schema.annotate(key, value);
		return this;
	}

	public SchemaBuilder inverseTypeAttribute(String attributeName, String referencedAttributeHolderName, String referencedAttributeName) {
		attribute(attributeName, InverseAttribute.class);
		Type type = assertTypeExists(referencedAttributeHolderName);
		attributeValue("referencedAttributeHolder", type);
		attributeValue("referencedAttributeName", referencedAttributeName);
		inverseAttributes.add((InverseAttribute) currentAttribute);
		return this;
	}

	public SchemaBuilder inverseMixinAttribute(String attributeName, String referencedAttributeHolderName, String referencedAttributeName) {
		attribute(attributeName, InverseAttribute.class);
		Mixin mixin = assertMixinExists(referencedAttributeHolderName);
		attributeValue("referencedAttributeHolder", mixin);
		attributeValue("referencedAttributeName", referencedAttributeName);
		inverseAttributes.add((InverseAttribute) currentAttribute);
		return this;
	}

	public SchemaBuilder binaryAttribute(String attributeName) {
		attribute(attributeName, BinaryAttribute.class);
		return this;
	}

	public SchemaBuilder jsonTypeAttribute(String attributeName, String typeName) {
		attribute(attributeName, JSONAttribute.class);
		Type type = assertTypeExists(typeName);
		attributeValue("namedAttributeHolder", type);
		return this;
	}

	public SchemaBuilder typeAttribute(String attributeName, String typeName) {
		attribute(attributeName, TypeAttribute.class);
		Type type = assertTypeExists(typeName);
		attributeValue("type", type);
		if (type.isVirtual()) {
			virtual();
		}
		return this;
	}

	public SchemaBuilder jsonMixinAttribute(String attributeName, String mixinName) {
		attribute(attributeName, JSONAttribute.class);
		Mixin mixin = assertMixinExists(mixinName);
		attributeValue("namedAttributeHolder", mixin);
		return this;
	}

	public SchemaBuilder mixinAttribute(String attributeName, String mixinName) {
		attribute(attributeName, MixinAttribute.class);
		Mixin mixin = assertMixinExists(mixinName);
		attributeValue("mixin", mixin);
		if (mixin.isVirtual()) {
			virtual();
		}
		return this;
	}

	public SchemaBuilder attribute(String name, Class attributeType) {
		if (currentAttributeHolder != null) {
			try {
				List attributes = currentAttributeHolder.getAttributes();
				Attribute attribute = null;
				if (attributes != null) {
					for (Attribute a : attributes) {
						if (name.equals(a.getName())) {
							// assert that the attribute matches the desired attribute type
							attributeType.cast(a);
							attribute = a;
						}
					}
				}
				if (attribute == null) {
					attribute = attributeType.newInstance();
					attribute.setName(name);
					if (attributes == null) {
						attributes = new ArrayList<>();
						currentAttributeHolder.setAttributes(attributes);
					}
					attributes.add(attribute);
				}
				if (currentAttributeHolder.isVirtual()) {
					attribute.setVirtual(true);
				}
				currentAttribute = attribute;
			} catch (InstantiationException | IllegalAccessException ex) {
				// ignore this
			}
		}
		return this;
	}

	public SchemaBuilder attributeValue(String propertyName, Object value) {
		if (currentAttribute != null) {
			Method[] methods = currentAttribute.getClass().getMethods();
			String setterName = "set" + propertyName.substring(0, 1).toUpperCase();
			if (propertyName.length() > 1) {
				setterName += propertyName.substring(1);
			}
			for (Method method : methods) {
				if (setterName.equals(method.getName())) {
					try {
						method.invoke(currentAttribute, value);
					} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
						// ignore this
					}
				}
			}
		}
		return this;
	}
	
	public SchemaBuilder indexAttribute() {
		if (currentAttribute != null) {
			currentAttribute.setIndexed(true);
		}
		return this;
	}
	
	public SchemaBuilder preventIndexAttribute() {
		if (currentAttribute != null) {
			currentAttribute.setIndexed(false);
		}
		return this;
	}

	public SchemaBuilder nullOnDelete() {
		return attributeValue("nullOnDelete", true);
	}

	public SchemaBuilder cascadeDelete() {
		return attributeValue("cascadeDelete", true);
	}

	public SchemaBuilder deleteOrphans() {
		return attributeValue("deleteOrphans", true);
	}
	
	public SchemaBuilder toOneAttribute(String attributeName) {
		return attributeValue("toOneAttribute", attributeName);
	}

	public SchemaBuilder virtual() {
		if (currentAttribute != null) {
			currentAttribute.setVirtual(true);
		}
		return this;
	}

	public SchemaBuilder nonVirtual() {
		if (currentAttribute != null) {
			currentAttribute.setVirtual(false);
		}
		return this;
	}

	public SchemaBuilder mandatory() {
		if (currentAttribute != null) {
			currentAttribute.setMandatory(true);
		}
		return this;
	}

	public SchemaBuilder unique(String... attributeNames) {
		if (currentAttributeHolder != null) {
			UniqueConstraint c = new UniqueConstraint();
			c.setHolder(currentAttributeHolder);
			List participatingAttributes = new ArrayList<>();
			c.setAttributes(participatingAttributes);
			if (attributeNames == null || attributeNames.length == 0) {
				if (currentAttribute != null) {
					participatingAttributes.add(currentAttribute);
				}
			} else {
				Map atts = SchemaUtil.collectAttributesAsMap(currentAttributeHolder);
				for (String attributeName : attributeNames) {
					Attribute att = atts.get(attributeName);
					if (att == null) {
						throw new IllegalArgumentException("could not find attribute " + attributeName + " for attribute holder " + currentAttributeHolder.getName());
					}
					participatingAttributes.add(att);
				}
			}
			if (!participatingAttributes.isEmpty()) {
				List uq = schema.getUniqueConstraints();
				if (uq == null) {
					uq = new ArrayList<>();
					schema.setUniqueConstraints(uq);
				}
				uq.add(c);
			}
		}
		return this;
	}

	public SchemaBuilder mixWith(String name) {
		if (currentType != null) {
			List mixins = currentType.getMixins();
			if (mixins != null) {
				for (Mixin mixin : mixins) {
					if (name.equals(mixin.getName())) {
						return this;
					}
				}
			} else {
				mixins = new ArrayList<>();
				currentType.setMixins(mixins);
			}
			Mixin mixin = assertMixinExists(name);
			mixins.add(mixin);
			List mixedInto = mixin.getMixedInto();
			if (mixedInto == null) {
				mixedInto = new ArrayList<>();
				mixin.setMixedInto(mixedInto);
			} else {
				for (Type type : mixedInto) {
					if (type == currentType) {
						return this;
					}
				}
			}
			mixedInto.add(currentType);
		}
		return this;
	}

	public SchemaBuilder virtualMixin(String name) {
		Mixin mixin = assertMixinExists(name);
		mixin.setVirtual(true);
		currentMixin = mixin;
		currentAttributeHolder = mixin;
		return this;
	}

	public SchemaBuilder mixin(String name) {
		Mixin mixin = assertMixinExists(name);
		currentMixin = mixin;
		currentAttributeHolder = mixin;
		return this;
	}

	private Type assertTypeExists(String name) {
		if (name == null) {
			throw new IllegalArgumentException("name of type is not allowed to be null");
		}
		Type type = typesByName.get(name);
		if (type == null) {
			type = new Type(schema);
			type.setName(name);
			typesByName.put(name, type);
			namedAttributeHoldersByName.put(name, type);
			List types = schema.getTypes();
			if (types == null) {
				types = new ArrayList<>();
				schema.setTypes(types);
			}
			types.add(type);
		}
		return type;
	}

	private Mixin assertMixinExists(String name) {
		if (name == null) {
			throw new IllegalArgumentException("name of mixin is not allowed to be null");
		}
		Mixin mixin = mixinsByName.get(name);
		if (mixin == null) {
			mixin = new Mixin(schema);
			mixin.setName(name);
			mixinsByName.put(name, mixin);
			namedAttributeHoldersByName.put(name, mixin);
			List mixins = schema.getMixins();
			if (mixins == null) {
				mixins = new ArrayList<>();
				schema.setMixins(mixins);
			}
			mixins.add(mixin);
		}
		return mixin;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy