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

org.springsource.loaded.SSMgr Maven / Gradle / Ivy

There is a newer version: 1.2.8.RELEASE
Show newest version
/*
 * Copyright 2010-2012 VMware and contributors
 *
 * 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.
 */

package org.springsource.loaded;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Static State Manager. The top most class in every hierarchy of reloadable types gets a static state manager instance.
 * The static state manager is used to find the value of a field for a particular object instance. The FieldAccessor is
 * added to the top most type in a reloadable hierarchy and is accessible to all the subtypes. It maintains a map from
 * type names to fields (name/value pairs).
 * 
 * @author Andy Clement
 * @since 0.5.0
 */
public class SSMgr {

	private static Logger log = Logger.getLogger(SSMgr.class.getName());

	Map> values = new HashMap>();

	public Object getValue(ReloadableType rtype, String name) throws IllegalAccessException {
		//		System.out.println("SSMgr.getValue(rtype=" + rtype + ",name=" + name + ")");
		Object result = null;
		// quick look to see if it is nearby (searches up supertype hierarchy, but only up to the topmost reloadabletype)
		FieldMember fieldmember = rtype.findStaticField(name);//InstanceField(name);

		// Why can fieldmember be null?
		// 1. Field really does not exist - shouldn't really be possible if the code is 'valid'
		// 2. Field is inherited from a supertype (usually because a reload has occurred)
		if (fieldmember == null) {
			FieldReaderWriter flr = rtype.locateField(name);
			if (flr == null) {
				log.info("Unexpectedly unable to locate static field " + name + " starting from type "
						+ rtype.dottedtypename
						+ ": clinit running late?");
				return null;
			}
			result = flr.getStaticFieldValue(rtype.getClazz(), this);
		}
		else {
			if (!fieldmember.isStatic()) {
				throw new IncompatibleClassChangeError("Expected static field " + rtype.dottedtypename + "."
						+ fieldmember.getName());
			}
			String declaringTypeName = fieldmember.getDeclaringTypeName();
			Map typeLevelValues = values.get(declaringTypeName);
			boolean knownField = false;
			if (typeLevelValues != null) {
				knownField = typeLevelValues.containsKey(name);
			}
			if (knownField) {
				result = typeLevelValues.get(name);
			}
			// If a field has been deleted it may 'reveal' a field in a supertype.  The revealed field may be in a type
			// not yet dealt with.  In this case typeLevelValues may be null (type not seen before) or the typelevelValues
			// may not have heard of our field name.  In these cases we need to go and find the field and 'relocate' it
			// into our map, where it will be processed from now on.

			// These revealed fields are not necessarily in the original form of the type so cannot always be accessed via reflection
			if (typeLevelValues == null || !knownField) {
				// TODO lookup performance?
				FieldMember fieldOnOriginalType = rtype.getTypeRegistry().getReloadableType(declaringTypeName).getTypeDescriptor()
						.getField(name);

				if (fieldOnOriginalType != null) {
					// Copy that field into the map... where it is going to live from now on
					ReloadableType rt = rtype.getTypeRegistry().getReloadableType(fieldmember.getDeclaringTypeName());
					try {
						Field f = rt.getClazz().getDeclaredField(name);
						f.setAccessible(true);
						result = f.get(null);
						if (typeLevelValues == null) {
							typeLevelValues = new HashMap();
							values.put(declaringTypeName, typeLevelValues);
						}
						typeLevelValues.put(name, result);
					}
					catch (Exception e) {
						throw new IllegalStateException("Unexpectedly unable to access field " + name + " on type "
								+ rt.getClazz().getName(), e);
					}
				}
				else {
					// The field was not on the original type.  As not seen before, can default it
					result = Utils.toResultCheckIfNull(null, fieldmember.getDescriptor());
					if (typeLevelValues == null) {
						typeLevelValues = new HashMap();
						values.put(declaringTypeName, typeLevelValues);
					}
					typeLevelValues.put(name, result);
					return result;
				}
			}

			if (result != null) {
				result = Utils.checkCompatibility(rtype.getTypeRegistry(), result, fieldmember.getDescriptor());
				if (result == null) {
					typeLevelValues.remove(fieldmember.getName());
				}
			}
			result = Utils.toResultCheckIfNull(result, fieldmember.getDescriptor());
		}
		//		if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.FINER)) {
		//			log.finer(" typeValues = values.get(fieldmember.getDeclaringTypeName());//rtype.getName());
			if (typeValues == null) {
				typeValues = new HashMap();
				values.put(fieldmember.getDeclaringTypeName(), typeValues);
			}
			typeValues.put(name, newValue);
		}
	}

	private String valuesToString() {
		StringBuilder s = new StringBuilder();
		s.append("FieldAccessor:" + System.identityHashCode(this)).append("\n");
		for (Map.Entry> entry : values.entrySet()) {
			s.append("Type " + entry.getKey()).append("\n");
			for (Map.Entry entry2 : entry.getValue().entrySet()) {
				s.append(" " + entry2.getKey() + "=" + entry2.getValue()).append("\n");
			}
		}
		return s.toString();
	}

	public String toString() {
		return valuesToString();
	}

	Map> getMap() {
		return values;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy