/**
* GRANITE DATA SERVICES
* Copyright (C) 2006-2015 GRANITE DATA SERVICES S.A.S.
*
* This file is part of the Granite Data Services Platform.
*
* Granite Data Services is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Granite Data Services is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA, or see <http://www.gnu.org/licenses/>.
*/
package org.granite.client.javafx.platform;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javafx.beans.value.ObservableBooleanValue;
import javafx.beans.value.ObservableDoubleValue;
import javafx.beans.value.ObservableFloatValue;
import javafx.beans.value.ObservableIntegerValue;
import javafx.beans.value.ObservableLongValue;
import javafx.beans.value.ObservableStringValue;
import javafx.beans.value.ObservableValue;
import javafx.beans.value.WritableBooleanValue;
import javafx.beans.value.WritableDoubleValue;
import javafx.beans.value.WritableFloatValue;
import javafx.beans.value.WritableIntegerValue;
import javafx.beans.value.WritableListValue;
import javafx.beans.value.WritableLongValue;
import javafx.beans.value.WritableMapValue;
import javafx.beans.value.WritableSetValue;
import javafx.beans.value.WritableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.ObservableMap;
import javafx.collections.ObservableSet;
import org.granite.client.javafx.persistence.collection.FXPersistentCollections;
import org.granite.client.persistence.collection.PersistentBag;
import org.granite.client.persistence.collection.PersistentList;
import org.granite.client.persistence.collection.PersistentMap;
import org.granite.client.persistence.collection.PersistentSet;
import org.granite.client.persistence.collection.PersistentSortedMap;
import org.granite.client.persistence.collection.PersistentSortedSet;
import org.granite.client.persistence.collection.UnsafePersistentCollection;
import org.granite.messaging.reflect.Property;
import com.sun.javafx.collections.ObservableListWrapper;
import com.sun.javafx.collections.ObservableMapWrapper;
import com.sun.javafx.collections.ObservableSetWrapper;
/**
* @author Franck WOLFF
*/
public abstract class AbstractJavaFXProperty implements JavaFXProperty {
private static final Field observableListWrapperField;
static {
try {
observableListWrapperField = ObservableListWrapper.class.getDeclaredField("backingList");
observableListWrapperField.setAccessible(true);
}
catch (Throwable t) {
throw new ExceptionInInitializerError("Could not find backingList field in: " + ObservableListWrapper.class.getName());
}
}
private static final Field observableSetWrapperField;
static {
try {
observableSetWrapperField = ObservableSetWrapper.class.getDeclaredField("backingSet");
observableSetWrapperField.setAccessible(true);
}
catch (Throwable t) {
throw new ExceptionInInitializerError("Could not find backingSet field in: " + ObservableSetWrapper.class.getName());
}
}
private static final Field observableMapWrapperField;
static {
try {
observableMapWrapperField = ObservableMapWrapper.class.getDeclaredField("backingMap");
observableMapWrapperField.setAccessible(true);
}
catch (Throwable t) {
throw new ExceptionInInitializerError("Could not find backingMap field in: " + ObservableMapWrapper.class.getName());
}
}
protected final Property property;
public AbstractJavaFXProperty(Property property) {
this.property = property;
}
@Override
public String getName() {
return property.getName();
}
@Override
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
return property.isAnnotationPresent(annotationClass);
}
@Override
public boolean isReadable() {
return property.isReadable();
}
@Override
public boolean isWritable() {
return property.isWritable();
}
@Override
public Class<?> getType() {
Class<?> type = property.getType();
if (ObservableValue.class.isAssignableFrom(type)) {
if (ObservableBooleanValue.class.isAssignableFrom(type))
return Boolean.TYPE;
if (ObservableIntegerValue.class.isAssignableFrom(type))
return Integer.TYPE;
if (ObservableLongValue.class.isAssignableFrom(type))
return Long.TYPE;
if (ObservableDoubleValue.class.isAssignableFrom(type))
return Double.TYPE;
if (ObservableFloatValue.class.isAssignableFrom(type))
return Float.TYPE;
if (ObservableStringValue.class.isAssignableFrom(type))
return String.class;
return Object.class;
}
return type;
}
@Override
public boolean getBoolean(Object holder) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (ObservableBooleanValue.class.isAssignableFrom(property.getType()))
return ((ObservableBooleanValue)property.getObject(holder)).get();
return property.getBoolean(holder);
}
@Override
public char getChar(Object holder) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (ObservableValue.class.isAssignableFrom(property.getType()))
throw new UnsupportedOperationException("JavaFX doesn't support char properties");
return property.getChar(holder);
}
@Override
public byte getByte(Object holder) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (ObservableValue.class.isAssignableFrom(property.getType()))
throw new UnsupportedOperationException("JavaFX doesn't support byte properties");
return property.getByte(holder);
}
@Override
public short getShort(Object holder) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (ObservableValue.class.isAssignableFrom(property.getType()))
throw new UnsupportedOperationException("JavaFX doesn't support short properties");
return property.getShort(holder);
}
@Override
public int getInt(Object holder) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (ObservableIntegerValue.class.isAssignableFrom(property.getType()))
return ((ObservableIntegerValue)property.getObject(holder)).get();
return property.getInt(holder);
}
@Override
public long getLong(Object holder) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (ObservableLongValue.class.isAssignableFrom(property.getType()))
return ((ObservableLongValue)property.getObject(holder)).get();
return property.getLong(holder);
}
@Override
public float getFloat(Object holder) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (ObservableFloatValue.class.isAssignableFrom(property.getType()))
return ((ObservableFloatValue)property.getObject(holder)).get();
return property.getFloat(holder);
}
@Override
public double getDouble(Object holder) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (ObservableDoubleValue.class.isAssignableFrom(property.getType()))
return ((ObservableDoubleValue)property.getObject(holder)).get();
return property.getDouble(holder);
}
@Override
public Object getRawObject(Object holder) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Object fieldValue = property.getObject(holder);
if (fieldValue instanceof ObservableValue)
return ((ObservableValue<?>)fieldValue).getValue();
return fieldValue;
}
@Override
public Object getObject(Object holder) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Object fieldValue = property.getObject(holder);
if (fieldValue instanceof ObservableValue) {
Object wrappedValue = ((ObservableValue<?>)fieldValue).getValue();
if (wrappedValue instanceof UnsafePersistentCollection)
return ((UnsafePersistentCollection<?>)wrappedValue).internalPersistentCollection();
if (wrappedValue instanceof ObservableListWrapper)
return observableListWrapperField.get(wrappedValue);
if (wrappedValue instanceof ObservableSetWrapper)
return observableSetWrapperField.get(wrappedValue);
if (wrappedValue instanceof ObservableMapWrapper)
return observableMapWrapperField.get(wrappedValue);
return wrappedValue;
}
return fieldValue;
}
@Override
public void setBoolean(Object holder, boolean value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (WritableBooleanValue.class.isAssignableFrom(property.getType()))
((WritableBooleanValue)property.getObject(holder)).set(value);
else
property.setBoolean(holder, value);
}
@Override
public void setChar(Object holder, char value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (WritableValue.class.isAssignableFrom(property.getType()))
throw new UnsupportedOperationException("JavaFX doesn't support char properties");
property.setChar(holder, value);
}
@Override
public void setByte(Object holder, byte value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (WritableValue.class.isAssignableFrom(property.getType()))
throw new UnsupportedOperationException("JavaFX doesn't support byte properties");
property.setByte(holder, value);
}
@Override
public void setShort(Object holder, short value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (WritableValue.class.isAssignableFrom(property.getType()))
throw new UnsupportedOperationException("JavaFX doesn't support short properties");
property.setShort(holder, value);
}
@Override
public void setInt(Object holder, int value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (WritableIntegerValue.class.isAssignableFrom(property.getType()))
((WritableIntegerValue)property.getObject(holder)).set(value);
else
property.setInt(holder, value);
}
@Override
public void setLong(Object holder, long value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (WritableLongValue.class.isAssignableFrom(property.getType()))
((WritableLongValue)property.getObject(holder)).set(value);
else
property.setLong(holder, value);
}
@Override
public void setFloat(Object holder, float value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (WritableFloatValue.class.isAssignableFrom(property.getType()))
((WritableFloatValue)property.getObject(holder)).set(value);
else
property.setFloat(holder, value);
}
@Override
public void setDouble(Object holder, double value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (WritableDoubleValue.class.isAssignableFrom(property.getType()))
((WritableDoubleValue)property.getObject(holder)).set(value);
else
property.setDouble(holder, value);
}
@Override
@SuppressWarnings("unchecked")
public void setObject(Object holder, Object value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Class<?> fieldType = property.getType();
if (WritableValue.class.isAssignableFrom(fieldType)) {
WritableValue<Object> writableValue = (WritableValue<Object>)property.getObject(holder);
if (writableValue instanceof WritableListValue) {
if (value instanceof PersistentBag)
value = FXPersistentCollections.observablePersistentBag((PersistentBag<Object>)value);
else if (value instanceof PersistentList)
value = FXPersistentCollections.observablePersistentList((PersistentList<Object>)value);
else if (value != null && !(value instanceof ObservableList<?>))
value = FXCollections.observableList((List<Object>)value);
}
else if (writableValue instanceof WritableSetValue) {
if (value instanceof PersistentSortedSet)
value = FXPersistentCollections.observablePersistentSortedSet((PersistentSortedSet<Object>)value);
else if (value instanceof PersistentSet)
value = FXPersistentCollections.observablePersistentSet((PersistentSet<Object>)value);
else if (value != null && !(value instanceof ObservableSet<?>))
value = FXCollections.observableSet((Set<Object>)value);
}
else if (writableValue instanceof WritableMapValue) {
if (value instanceof PersistentSortedMap)
value = FXPersistentCollections.observablePersistentSortedMap((PersistentSortedMap<Object, Object>)value);
else if (value instanceof PersistentMap)
value = FXPersistentCollections.observablePersistentMap((PersistentMap<Object, Object>)value);
else if (value != null && !(value instanceof ObservableMap<?, ?>))
value = FXCollections.observableMap((Map<Object, Object>)value);
}
/**
*
* A bound property cannot be set!!!
*
*
*/
if(!((javafx.beans.property.Property)writableValue).isBound())
writableValue.setValue(value);
}
else
property.setObject(holder, value);
}
@Override
public boolean equals(Object obj) {
return property.equals(obj);
}
@Override
public int hashCode() {
return property.hashCode();
}
@Override
public String toString() {
return property.toString();
}
}