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

org.springframework.ldap.odm.core.impl.ObjectMetaData Maven / Gradle / Ivy

/*
 * Copyright 2005-2013 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.ldap.odm.core.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ldap.odm.annotations.Entry;
import org.springframework.ldap.odm.annotations.Id;
import org.springframework.ldap.support.LdapUtils;
import org.springframework.util.StringUtils;

import javax.naming.Name;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

/*
 * An internal class to process the meta-data and reflection data for an entry.
 * 
 * @author Paul Harvey <paul.at.pauls-place.me.uk>
 */
/* package */ final class ObjectMetaData implements Iterable {
	private static final Logger LOG = LoggerFactory.getLogger(ObjectMetaData.class);

	private AttributeMetaData idAttribute;

	private Map fieldToAttribute = new HashMap();

	private Set dnAttributes = new TreeSet(new Comparator() {
		@Override
		public int compare(AttributeMetaData a1, AttributeMetaData a2) {
			if(!a1.isDnAttribute() || !a2.isDnAttribute()) {
				// Not interesting to compare these.
				return 0;
			}

			return Integer.valueOf(a1.getDnAttribute().index()).compareTo(a2.getDnAttribute().index());
		}
	});

	private boolean indexedDnAttributes = false;

	private Set objectClasses = new LinkedHashSet();

	private Name base = LdapUtils.emptyLdapName();

	public Set getObjectClasses() {
		return objectClasses;
	}

	public AttributeMetaData getIdAttribute() {
		return idAttribute;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Iterable#iterator()
	 */
	public Iterator iterator() {
		return fieldToAttribute.keySet().iterator();
	}

	public AttributeMetaData getAttribute(Field field) {
		return fieldToAttribute.get(field);
	}
	
	public ObjectMetaData(Class clazz) {
		if (LOG.isDebugEnabled()) {
			LOG.debug(String.format("Extracting metadata from %1$s", clazz));
		}
		
		// Get object class metadata - the @Entity annotation
		Entry entity = clazz.getAnnotation(Entry.class);
		if (entity != null) {
			// Default objectclass name to the class name unless it's specified
			// in @Entity(name={objectclass1, objectclass2});
			String[] localObjectClasses = entity.objectClasses();
			if (localObjectClasses != null && localObjectClasses.length > 0 && localObjectClasses[0].length() > 0) {
				for (String localObjectClass:localObjectClasses) {
					objectClasses.add(new CaseIgnoreString(localObjectClass));
				}
			} else {
				objectClasses.add(new CaseIgnoreString(clazz.getSimpleName()));
			}

			String base = entity.base();
			if(StringUtils.hasText(base)) {
				this.base = LdapUtils.newLdapName(base);
			}
		} else {
			throw new MetaDataException(String.format("Class %1$s must have a class level %2$s annotation", clazz,
					Entry.class));
		}

		// Check the class is final
		if (!Modifier.isFinal(clazz.getModifiers())) {
			LOG.warn(String.format("The Entry class %1$s should be declared final", clazz.getSimpleName()));
		}

		// Get field meta-data - the @Attribute annotation
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			// So we can write to private fields
			field.setAccessible(true);

			// Skip synthetic or static fields
			if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) {
				continue;
			}

			AttributeMetaData currentAttributeMetaData=new AttributeMetaData(field);
			if (currentAttributeMetaData.isId()) {
				if (idAttribute!=null) {
					// There can be only one id field
					throw new MetaDataException(
						  String.format("You man have only one field with the %1$s annotation in class %2$s", Id.class, clazz));
				}
				idAttribute=currentAttributeMetaData;
			}
			fieldToAttribute.put(field, currentAttributeMetaData);

			if(currentAttributeMetaData.isDnAttribute()) {
				dnAttributes.add(currentAttributeMetaData);
			}
		}

		if (idAttribute == null) {
			throw new MetaDataException(
					String.format("All Entry classes must define a field with the %1$s annotation, error in class %2$s", Id.class,
								  clazz));
		}

		postProcessDnAttributes(clazz);

		if (LOG.isDebugEnabled()) {
			LOG.debug(String.format("Extracted metadata from %1$s as %2$s", clazz, this));
		}
	}

	private void postProcessDnAttributes(Class clazz) {
		boolean hasIndexed = false;
		boolean hasNonIndexed = false;

		for (AttributeMetaData dnAttribute : dnAttributes) {
			int declaredIndex = dnAttribute.getDnAttribute().index();

			if(declaredIndex != -1) {
				hasIndexed = true;
			}

			if(declaredIndex == -1) {
				hasNonIndexed = true;
			}
		}

		if(hasIndexed && hasNonIndexed) {
			throw new MetaDataException(String.format("At least one DnAttribute declared on class %s is indexed, " +
					"which means that all DnAttributes must be indexed", clazz.toString()));
		}

		indexedDnAttributes = hasIndexed;
	}

	int size() {
		return fieldToAttribute.size();
	}

	boolean canCalculateDn() {
		return dnAttributes.size() > 0 && indexedDnAttributes;
	}

	public Set getDnAttributes() {
		return dnAttributes;
	}

	Name getBase() {
		return base;
	}

	/*
		 * (non-Javadoc)
		 *
		 * @see java.lang.Object#toString()
		 */
	@Override
	public String toString() {
		return String.format("objectsClasses=%1$s | idField=%2$s | attributes=%3$s", 
				objectClasses, idAttribute.getName(), fieldToAttribute);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy