/* * Encog(tm) Core v2.5 - Java Version * http://www.heatonresearch.com/encog/ * http://code.google.com/p/encog-java/ * Copyright 2008-2010 Heaton Research, Inc. * * 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. * * For more information on Heaton Research copyrights, licenses * and trademarks visit: * http://www.heatonresearch.com/copyright */ package org.encog.persist.persistors.generic; import java.lang.reflect.Field; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.encog.persist.EncogPersistedObject; import org.encog.persist.PersistError; import org.encog.persist.annotations.EGReferenceable; import org.encog.util.obj.ReflectionUtil; /** * The object tagger is used in generic persistence to tag objects with a * reference number. * */ public class ObjectTagger { /** * The map of object to reference number. */ private final Map<Object, Integer> map = new HashMap<Object, Integer>(); /** * THe current reference ID. */ private int currentID = 1; /** * The current depth. */ private int depth; /** * Analyze the specified object and build a reference map. * * @param encogObject * The object to analyze. */ public void analyze(final EncogPersistedObject encogObject) { try { this.depth = 0; assignObjectTag(encogObject); for (final Field childField : ReflectionUtil .getAllFields(encogObject.getClass())) { if (ReflectionUtil.shouldAccessField(childField, true)) { childField.setAccessible(true); final Object childValue = childField.get(encogObject); tagField(childValue); } } } catch (final IllegalAccessException e) { throw new PersistError(e); } } /** * Assign a reference number to the specified object. * @param obj The object to "tag". */ private void assignObjectTag(final Object obj) { if (obj.getClass().getAnnotation(EGReferenceable.class) != null) { this.map.put(obj, this.currentID); this.currentID++; } } /** * Clear the map and current id. */ public void clear() { this.map.clear(); this.currentID = 1; } /** * Get the reference for the specified object. * @param obj The object to check. * @return -1 for no reference, otherwise the reference numebr. */ public int getReference(final Object obj) { if (obj == null) { return -1; } return this.map.get(obj); } /** * Returns true if the object has a reference. * @param obj The object to check. * @return True if the object has a reference. */ public boolean hasReference(final Object obj) { return this.map.containsKey(obj); } /** * Tag a collection, every object in the collection will be a reference. * @param value The collection to tag. * @throws IllegalAccessException An error. */ private void tagCollection(final Collection< ? > value) throws IllegalAccessException { for (final Object obj : value) { tagObject(obj); } } /** * Tag a field. * @param fieldObject The field to tag. * @throws IllegalAccessException An error. */ private void tagField(final Object fieldObject) throws IllegalAccessException { this.depth++; if (this.map.containsKey(fieldObject)) { return; } if (fieldObject != null) { if (fieldObject instanceof Collection < ? >) { tagCollection((Collection< ? >) fieldObject); } else { tagObject(fieldObject); } } this.depth--; } /** * Tag an object. * @param parentObject The object to tag. * @throws IllegalAccessException An error. */ private void tagObject(final Object parentObject) throws IllegalAccessException { final Collection<Field> allFields = ReflectionUtil .getAllFields(parentObject.getClass()); assignObjectTag(parentObject); // handle actual fields for (final Field childField : allFields) { childField.setAccessible(true); if (ReflectionUtil.shouldAccessField(childField, false)) { final Object childValue = childField.get(parentObject); if (!ReflectionUtil.isPrimitive(childValue) && !ReflectionUtil.isSimple(childValue)) { if (this.depth > 50) { throw new PersistError( "Encog persistence is greater than 50 levels deep, closed loop likely. Consider adding @EGReference tag near attribute: " + parentObject.getClass().toString()); } if (!this.map.containsKey(childValue)) { tagField(childValue); } } } } } }