/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.modules;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
/**
* A simple implementation of a strongly typed named property
*
* <p>Initial date: May 6, 2016
* @author lmihalkovic, http://www.frentix.com
*/
public abstract class ModuleProperty<T> {
/**
* A strongly typed property value
*
* Initial date: May 6, 2016<br>
* @author lmihalkovic, http://www.frentix.com
*
*/
public static final class ModulePropertyValue<X> {
private X value;
private final ModuleProperty<X> def;
protected ModulePropertyValue(X value, ModuleProperty<X> def) {
this.value = value;
this.def = def;
}
public X val() {
if(!isSet()) return getDefault();
return value;
}
public void val(X val) {
this.value = val;
}
public X getDefault() {
return def.getDefault();
}
public boolean isSet() {
return this.value != null;
}
public String name() {
return def.name;
}
}
private final String name;
private final T defaultValue;
private final Type type;
public ModuleProperty(String name) {
this(name, null);
}
public ModuleProperty(String name, T defaultValue) {
this.name = name;
this.defaultValue = defaultValue;
this.type = getType();
}
public ModulePropertyValue<T> val(T value) {
return new ModulePropertyValue<T>(value, this);
}
public String name() {
return this.name;
}
public boolean hasDefault() {
return defaultValue != null;
}
T getDefault() {
return this.defaultValue;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[")
.append(name())
.append(":")
.append(type);
if (defaultValue!= null) {
sb.append(" {").append(defaultValue).append("}");
}
sb.append("]");
return sb.toString();
}
// ------------------------------
// Internal
private Type getType() {
Type superclass = getClass().getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
return ((ParameterizedType) superclass).getActualTypeArguments()[0];
}
@SuppressWarnings("unchecked")
Class<T> rawType() {
// this is ok or leads to a CCE later if the types do not match
return (Class<T>) getRawType(type);
}
private static Class<?> getRawType(Type type) {
if (type instanceof Class<?>) {
// type is a class
return (Class<?>) type;
} else if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type rawType = parameterizedType.getRawType();
checkArgument(rawType instanceof Class);
return (Class<?>) rawType;
} else if (type instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) type).getGenericComponentType();
return Array.newInstance(getRawType(componentType), 0).getClass();
} else if (type instanceof TypeVariable) {
return Object.class;
} else if (type instanceof WildcardType) {
return getRawType(((WildcardType) type).getUpperBounds()[0]);
} else {
String className = type == null ? "null" : type.getClass().getName();
throw new IllegalArgumentException("Expected a Class, ParameterizedType, or " + "GenericArrayType, but <"
+ type + "> is of type " + className);
}
}
private static void checkArgument(boolean condition) {
if (!condition) {
throw new IllegalArgumentException();
}
}
}