package org.netbeans.gradle.model.internal;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicReference;
import org.netbeans.gradle.model.api.ProjectInfoBuilder2;
import org.netbeans.gradle.model.util.ReflectionUtils;
public final class EnumProjectInfoBuilderRef<T> implements ProjectInfoBuilder2<T>, BuilderWrapper {
private static final long serialVersionUID = 1L;
private final Class<? extends T> modelType;
private final String wrappedTypeName;
private final String wrappedConstName;
private final AtomicReference<ProjectInfoBuilder2<?>> wrappedRef;
public EnumProjectInfoBuilderRef(
Class<? extends T> modelType,
String wrappedTypeName) {
if (modelType == null) throw new NullPointerException("modelType");
if (wrappedTypeName == null) throw new NullPointerException("wrappedTypeName");
this.modelType = modelType;
this.wrappedTypeName = ReflectionUtils.updateTypeName(modelType, wrappedTypeName);
this.wrappedConstName = null;
this.wrappedRef = new AtomicReference<ProjectInfoBuilder2<?>>(null);
}
public EnumProjectInfoBuilderRef(
Class<? extends T> modelType,
String wrappedTypeName,
String wrappedConstName) {
if (modelType == null) throw new NullPointerException("modelType");
if (wrappedTypeName == null) throw new NullPointerException("wrappedTypeName");
if (wrappedConstName == null) throw new NullPointerException("wrappedConstName");
this.modelType = modelType;
this.wrappedTypeName = ReflectionUtils.updateTypeName(modelType, wrappedTypeName);
this.wrappedConstName = wrappedConstName;
this.wrappedRef = new AtomicReference<ProjectInfoBuilder2<?>>(null);
}
private static Object unsafeEnumValueOf(Class<?> type, String constName) {
Object[] enumConsts = type.getEnumConstants();
if (constName != null) {
for (Object enumConst: enumConsts) {
String name = ((Enum<?>)enumConst).name();
if (constName.equals(name)) {
return enumConst;
}
}
throw new IllegalStateException("No such enum constant for type " + type.getName() + ": " + constName);
}
else {
if (enumConsts.length != 1) {
throw new IllegalStateException("Cannot determine which enum const must be used: " + Arrays.asList(enumConsts));
}
return enumConsts[0];
}
}
private ProjectInfoBuilder2<?> createWrapped() {
try {
return (ProjectInfoBuilder2<?>)unsafeEnumValueOf(
Class.forName(wrappedTypeName, false, modelType.getClassLoader()),
wrappedConstName);
} catch (Exception ex) {
if (ex instanceof RuntimeException) {
throw (RuntimeException)ex;
}
throw new RuntimeException(ex);
}
}
private ProjectInfoBuilder2<?> getWrapped() {
ProjectInfoBuilder2<?> result = wrappedRef.get();
if (result == null) {
result = createWrapped();
if (!wrappedRef.compareAndSet(null, result)) {
result = wrappedRef.get();
}
}
return result;
}
public T getProjectInfo(Object project) {
Object result = getWrapped().getProjectInfo(project);
return modelType.cast(result);
}
public String getName() {
return getWrapped().getName();
}
public Object getWrappedObject() {
return null;
}
public Class<?> getWrappedType() {
return modelType;
}
private Object writeReplace() {
return new SerializedFormat(this);
}
private void readObject(ObjectInputStream stream) throws InvalidObjectException {
throw new InvalidObjectException("Use proxy.");
}
private static final class SerializedFormat implements Serializable {
private static final long serialVersionUID = 1L;
private final Class<?> modelType;
private final String wrappedTypeName;
private final String wrappedConstName;
public SerializedFormat(EnumProjectInfoBuilderRef<?> source) {
this.modelType = source.modelType;
this.wrappedTypeName = source.wrappedTypeName;
this.wrappedConstName = source.wrappedConstName;
}
private Object readResolve() throws ObjectStreamException {
return wrappedConstName != null
? new EnumProjectInfoBuilderRef<Object>(modelType, wrappedTypeName, wrappedConstName)
: new EnumProjectInfoBuilderRef<Object>(modelType, wrappedTypeName);
}
}
}