/*
* This file is protected by Copyright. Please refer to the COPYRIGHT file
* distributed with this source distribution.
*
* This file is part of REDHAWK core.
*
* REDHAWK core 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 3 of the License, or (at your
* option) any later version.
*
* REDHAWK core 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 program. If not, see http://www.gnu.org/licenses/.
*/
package org.ossie.properties;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.omg.CORBA.Any;
import org.omg.CORBA.ORB;
import org.omg.CORBA.TCKind;
import org.ossie.properties.AnyUtils;
import CF.DevicePackage.InvalidCapacity;
import CF.DevicePackage.InvalidState;
/**
* Internal class
*
* @param <T>
*/
abstract class Property<T extends Object> implements IProperty {
protected String id;
protected String name;
protected Mode mode;
protected Action action;
protected Set<Kind> kinds;
protected boolean optional;
protected T value;
protected List<PropertyListener<T>> changeListeners = new LinkedList<PropertyListener<T>>();
protected List<PropertyListener< Object >> voidListeners = new LinkedList<PropertyListener<Object >>();
protected Allocator<T> allocator = null;
protected Property(String id, String name, T value, Mode mode, Action action, Kind[] kinds) {
super();
this.id = id;
this.name = name;
this.value = value;
this.optional = false;
if (action == null) {
this.action = Action.EXTERNAL;
} else {
this.action = action;
}
if (mode == null) {
this.mode = Mode.READWRITE;
} else {
this.mode = mode;
}
this.kinds = new HashSet<Kind>();
if (kinds == null) {
// RESOLVE -- need to deprecate
this.kinds.add(Kind.CONFIGURE);
this.kinds.add(Kind.PROPERTY);
} else {
for (Kind kind : kinds) {
this.kinds.add(kind);
}
}
}
protected Property(String id, String name, T value, Mode mode, Action action, Kind[] kinds, boolean optional) {
super();
this.id = id;
this.name = name;
this.value = value;
this.optional = optional;
if (action == null) {
this.action = Action.EXTERNAL;
} else {
this.action = action;
}
if (mode == null) {
this.mode = Mode.READWRITE;
} else {
this.mode = mode;
}
this.kinds = new HashSet<Kind>();
if (kinds == null) {
// RESOLVE -- need to deprecate
this.kinds.add(Kind.CONFIGURE);
this.kinds.add(Kind.PROPERTY);
} else {
for (Kind kind : kinds) {
this.kinds.add(kind);
}
}
}
/**
* Updates the value of the property, triggering any change listeners.
*/
public void construct(Any any) {
T oldValue = this.value;
fromAny(any);
}
/**
* Updates the value of the property, triggering any change listeners.
*/
public void configureNoCallbacks(Any any) {
fromAny(any);
}
/**
* Updates the value of the property, triggering any change listeners.
*/
public void configure(Any any) {
boolean trigger_callback = false;
if (AnyUtils.compareAnys(this.toAny(), any, "ne")) {
trigger_callback = true;
}
T oldValue = this.value;
configureNoCallbacks(any);
if (trigger_callback) {
for (PropertyListener<T> listener : changeListeners) {
listener.valueChanged(oldValue, this.value);
}
for (PropertyListener<Object> listener : voidListeners) {
listener.valueChanged(oldValue, this.value);
}
}
}
/**
* Gets the current value of the property.
*/
public T getValue() {
return this.value;
}
/**
* Sets the current value of the property.
*/
public void setValue(T value) {
T tmpValue = this.value;
this.value = value;
for (PropertyListener<Object> listener : voidListeners) {
listener.valueChanged(value, tmpValue);
}
}
/**
* Registers a listener for changes to this property's value.
*/
public void addChangeListener(PropertyListener<T> listener) {
changeListeners.add(listener);
}
/**
* Unregisters a listener for changes to this property's value.
*/
public void removeChangeListener(PropertyListener<T> listener) {
changeListeners.remove(listener);
}
/**
* Registers a listener for changes to this property's value.
*/
public void addObjectListener(PropertyListener<Object> listener) {
voidListeners.add(listener);
}
/**
* Unregisters a listener for changes to this property's value.
*/
public void removeObjectListener(PropertyListener<Object> listener) {
voidListeners.remove(listener);
}
/**
* Attempts to allocate capacity from this property. If an allocator is
* set, the operation is delgated to the allocator.
*/
public boolean allocate(Any any) throws InvalidCapacity, InvalidState {
if (!isAllocatable()) {
throw new UnsupportedOperationException("Property " + this.id + " is not allocatable");
}
T capacity = fromAny_(any);
if (this.allocator != null) {
return this.allocator.allocate(capacity);
} else {
return allocate(capacity);
}
}
/**
* Default implementation of capacity allocation; always returns false (no
* allocation occurred). Subclasses that can handle allocation without a
* delegate (such as simple numeric properties) may override this method.
*/
protected boolean allocate(T capacity) {
return false;
}
/**
* Attempts to deallocate capacity from this property. If an allocator is
* set, the operation is delgated to the allocator.
*/
public void deallocate(Any any) throws InvalidCapacity, InvalidState {
if (!isAllocatable()) {
throw new UnsupportedOperationException("Property " + this.id + " is not allocatable");
}
T capacity = fromAny_(any);
if (this.allocator != null) {
this.allocator.deallocate(capacity);
} else {
deallocate(capacity);
}
}
/**
* Default implementation of capacity deallocation; does nothing.
* Subclasses that can handle deallocation without a delegate (such as
* simple numeric properties) may override this method.
*/
protected void deallocate(T capacity) {
}
public void fromAny(Any any) {
this.value = fromAny_(any);
}
protected abstract T fromAny_(Any any);
/**
* Set the delegate responsible for handling allocation and deallocation
* of this property.
*/
public void setAllocator(Allocator<T> listener) {
allocator = listener;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getMode() {
return mode.toString();
}
public String getAction() {
return action.toString();
}
public String[] getKinds() {
String[] ret = new String[this.kinds.size()];
int ii = 0;
for (Kind kind : this.kinds) {
ret[ii++] = kind.toString();
}
return ret;
}
public boolean isQueryable() {
if (this.kinds.contains(Kind.CONFIGURE) ||
this.kinds.contains(Kind.EXECPARAM) ||
this.isProperty() ) {
return (mode != Mode.WRITEONLY);
}
return false;
}
public boolean isProperty() {
if (this.kinds.contains(Kind.PROPERTY)) {
return true;
}
return false;
}
public boolean isConfigurable() {
if (this.kinds.contains(Kind.CONFIGURE) || this.isProperty() ) {
return (mode != Mode.READONLY);
}
return false;
}
public boolean isAllocatable() {
if (this.kinds.contains(Kind.ALLOCATION)) {
return (action == Action.EXTERNAL);
}
return false;
}
public boolean isEventable() {
return this.kinds.contains(Kind.EVENT);
}
public boolean isSet() {
boolean retval = false;
if (this.optional == true) {
if (this.getValue() instanceof List) {
if (!((List)this.getValue()).isEmpty()) {
retval = true;
}
} else {
if (this.getValue() != null) {
retval = true;
}
}
} else {
retval = true;
}
return retval;
}
}