
atom.view.AbstractView Maven / Gradle / Ivy
/*
* Copyright © 2014 Geeoz, and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Research Projects is dual-licensed under the GNU General Public
* License, version 2.0 (GPLv2) and the Geeoz Commercial License.
*
* Solely for non-commercial purposes. A purpose is non-commercial only if
* it is in no manner primarily intended for or directed toward commercial
* advantage or private monetary compensation.
*
* This Geeoz Software is supplied to you by Geeoz in consideration of your
* agreement to the following terms, and your use, installation, modification
* or redistribution of this Geeoz Software constitutes acceptance of these
* terms. If you do not agree with these terms, please do not use, install,
* modify or redistribute this Geeoz Software.
*
* Neither the name, trademarks, service marks or logos of Geeoz may be used
* to endorse or promote products derived from the Geeoz Software without
* specific prior written permission from Geeoz.
*
* The Geeoz Software is provided by Geeoz on an "AS IS" basis. GEEOZ MAKES NO
* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
* WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, REGARDING THE GEEOZ SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
* COMBINATION WITH YOUR PRODUCTS.
*
* IN NO EVENT SHALL GEEOZ BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
* AND/OR DISTRIBUTION OF THE GEEOZ SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER
* THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
* OTHERWISE, EVEN IF GEEOZ HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* A copy of the GNU General Public License is included in the distribution in
* the file LICENSE and at
*
* http://www.gnu.org/licenses/gpl-2.0.html
*
* If you are using the Research Projects for commercial purposes, we
* encourage you to visit
*
* http://products.geeoz.com/license
*
* for more details.
*
* This software or hardware and documentation may provide access to
* or information on content, products, and services from third parties.
* Geeoz and its affiliates are not responsible for and expressly disclaim
* all warranties of any kind with respect to third-party content, products,
* and services. Geeoz and its affiliates will not be responsible for any loss,
* costs, or damages incurred due to your access to or use of third-party
* content, products, or services. If a third-party content exists, the
* additional copyright notices and license terms applicable to portions of the
* software are set forth in the THIRD_PARTY_LICENSE_README file.
*
* Please contact Geeoz or visit www.geeoz.com if you need additional
* information or have any questions.
*/
package atom.view;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* This abstract class represents the basic change tracking support.
*
* @author Alex Voloshyn
* @author Serge Voloshyn
* @author Vladimir Ovcharov
* @version 1.15 9/25/14
*/
@XmlType(namespace = AbstractView.LAYOUT_NAMESPACE)
public abstract class AbstractView implements Serializable, ViewSearch {
/**
* Use serialVersionUID from JDK 1.0.2 for interoperability.
*/
private static final long serialVersionUID = -150771344243581601L;
/**
* JAXB manifest namespace.
*/
public static final String LAYOUT_NAMESPACE =
"http://atom.geeoz.com/layout/1.0";
/**
* The view's identifier.
*/
private String viewId;
/**
* Binary service's path responsible to file uploading.
*/
private String binaryPath;
/**
* The desired resource identifier.
*/
private String reference;
/**
* Property change support for current view.
*/
private transient PropertyChangeSupport support = null;
/**
* Is tracking now state.
*/
private transient boolean isTrackingNow = false;
/**
* Parent tracking entity.
*/
private transient AbstractView parent = null;
/**
* List with property change events.
*/
private transient Map changes = null;
/**
* Retrieve underlying resource filter.
*/
private transient Filter filter = null;
/**
* Simple constructor to use when creating a view from code.
*/
public AbstractView() {
super();
}
/**
* Simple constructor that creates View
with defined
* identifier.
*
* @param identify a string used to identify the view
* @see #setViewId(String)
*/
public AbstractView(final String identify) {
super();
viewId = identify;
}
/**
* Returns this view's identifier.
*
* @return a string used to identify the view or null
if the
* view has no ID
*/
@XmlAttribute(name = "id")
public final String getViewId() {
return viewId;
}
/**
* Sets the identifier for this view. The identifier does not have to be
* unique in this view's hierarchy.
*
* @param identify a string used to identify the view
*/
public final void setViewId(final String identify) {
viewId = identify;
}
/**
* Get binary service path responsible to file uploading.
*
* @return binary service path
*/
@XmlAttribute(name = "binary-path")
public final String getBinaryPath() {
return binaryPath;
}
/**
* Set the binary service path.
*
* @param aBinaryPath new binary service path
*/
public final void setBinaryPath(final String aBinaryPath) {
binaryPath = aBinaryPath;
}
/**
* Check that string could be a reference.
*
* @param string input string for check
* @return true if string is the reference
*/
private boolean isReference(final String string) {
return !(string == null || string.isEmpty()) && string.charAt(0) == '@';
}
/**
* Get the desired resource identifier.
*
* @return the desired resource identifier
*/
@XmlAttribute(name = "reference")
public String getReference() {
return reference;
}
/**
* Sets resource reference.
*
* @param string the desired resource identifier
*/
public void setReference(final String string) {
if (isReference(string)) {
reference = string;
}
}
/**
* Assign the parent if it exists, or null.
*
* @param object the parent tracking object
*/
protected final void assignParent(final AbstractView object) {
parent = object;
}
/**
* Return the parent if it exists, or null.
*
* @return the parent
*/
public final AbstractView getParent() {
return parent;
}
/**
* Parent object is not restored on unmarshal, so this method should
* help.
*
* @param unmarshaller an instance of the unmarshaller
* @param object parent object
*/
@SuppressWarnings("unused")
public final void afterUnmarshal(final Unmarshaller unmarshaller,
final Object object) {
assignParent((AbstractView) object);
}
/**
* Retrieve view that corresponding for change tracking.
*
* @return corresponding trackable view
*/
private AbstractView root() {
if (parent != null) {
return parent.root();
}
return this;
}
/**
* Build default property change support instance.
*
* @return new property change support instance.
*/
private PropertyChangeSupport getChangeSupport() {
final PropertyChangeSupport instance = new PropertyChangeSupport(this);
instance.addPropertyChangeListener(new DefaultChangeListener());
return instance;
}
/**
* Apply changes to view according to existing hierarchy.
*
* @param event property change event that should be applied
*/
public final void applyChange(final PropertyChangeEvent event) {
if (event == null) {
return;
}
try {
final Field field = getField(
this.getClass(),
event.getPropertyName());
AccessController.doPrivileged(
new AccessiblePrivilegedAction(field));
field.set(this, event.getNewValue());
} catch (ReflectiveOperationException fault) {
fault.printStackTrace();
}
}
/**
* Get field from class or super class.
*
* @param clazz class for field access
* @param fieldName name for search
* @return a field that was fined
* @throws NoSuchFieldException in case if field wasn't find
*/
private Field getField(final Class> clazz,
final String fieldName) throws NoSuchFieldException {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException fault) {
final Class> superClass = clazz.getSuperclass();
if (superClass == null) {
throw fault;
} else {
return getField(superClass, fieldName);
}
}
}
/**
* Apply changes to view according to existing hierarchy.
*
* @param events property change events that should be applied
*/
public final void applyChanges(final List events) {
if (events == null) {
return;
}
for (PropertyChangeEvent event : events) {
final View view = findViewById((String) event.getPropagationId());
if (view != null) {
view.applyChange(event);
}
}
}
/**
* Provide list of property change events.
*
* @return list of property change events
*/
public final List getChanges() {
if (root().changes == null) {
return null;
} else {
final List events =
new ArrayList<>(root().changes.values());
root().changes.clear();
return events;
}
}
/**
* Returns current tracking status.
*
* @return current tracking status
*/
public final boolean isTracking() {
return isTrackingNow;
}
/**
* Tests if this object has changed.
*
* @return true
if the object changes are not empty.
*/
public final boolean hasChanged() {
final Map events = root().changes;
return !(events == null || events.isEmpty());
}
/**
* Reports a bound property update to listeners that have been registered to
* track updates of all properties or a property with the specified name.
*
* @param propertyName the programmatic name of the property that was
* changed
* @param newValue the new value of the property
*/
protected final void fireChange(final String propertyName,
final Object newValue) {
if (!root().isTrackingNow) {
return;
}
final PropertyChangeEvent event;
if (newValue instanceof String) {
event = new PropertyChangeEvent(
this, propertyName, null, filter((String) newValue));
} else {
event = new PropertyChangeEvent(
this, propertyName, null, newValue);
}
event.setPropagationId(viewId);
if (support == null) {
support = getChangeSupport();
}
support.firePropertyChange(event);
}
/**
* Enable tracking changes for the view.
*/
public final void trackChanges() {
trackChanges(true);
}
/**
* Set status for tracking changes for the view.
*
* @param enable status for change tracking
*/
public final void trackChanges(final boolean enable) {
trackChanges(enable, true);
}
/**
* Set status for tracking changes for the view.
*
* @param enable status for change tracking
* @param clearExisting whether to clear existing changes or not
*/
public final void trackChanges(final boolean enable,
final boolean clearExisting) {
final AbstractView view = root();
view.isTrackingNow = enable;
final Map events = view.changes;
if (clearExisting && !enable && events != null) {
events.clear();
}
}
/**
* Sets resource filter reference.
*
* @param resources a resource filter
*/
public final void setFilter(final Filter resources) {
root().filter = resources;
}
/**
* Return the string value associated with a particular resource reference.
* It will be stripped of any styled text information.
*
* @param string the desired resource identifier
* @return the string data associated with the resource, stripped of styled
* text information or input reference if no value exists
*/
protected final String filter(final String string) {
final Filter resources = root().filter;
if (resources == null || !isReference(string)) {
return string;
}
final String value = resources.filter(string);
if (value != null) {
return value;
}
return string;
}
/**
* Default property change listener.
*/
@XmlTransient
private class DefaultChangeListener implements PropertyChangeListener {
@Override
public final void propertyChange(final PropertyChangeEvent evt) {
Map events = root().changes;
if (events == null) {
events = new HashMap<>();
root().changes = events;
}
final String key = String.valueOf(
evt.getPropagationId()).concat(evt.getPropertyName());
events.put(key, evt);
}
}
/**
* Provide accessible change.
*/
@XmlTransient
private static class AccessiblePrivilegedAction
implements PrivilegedAction {
/**
* Field for accessible change.
*/
private final transient Field field;
/**
* @param aField field to change accessible
*/
AccessiblePrivilegedAction(final Field aField) {
field = aField;
}
@Override
public Void run() {
field.setAccessible(true);
return null; // nothing to return
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy