com.flexive.shared.structure.FxPropertyAssignmentEdit.java Source code

Java tutorial

Introduction

Here is the source code for com.flexive.shared.structure.FxPropertyAssignmentEdit.java

Source

/***************************************************************
 *  This file is part of the [fleXive](R) framework.
 *
 *  Copyright (c) 1999-2014
 *  UCS - unique computing solutions gmbh (http://www.ucs.at)
 *  All rights reserved
 *
 *  The [fleXive](R) project is free software; you can redistribute
 *  it and/or modify it under the terms of the GNU Lesser General Public
 *  License version 2.1 or higher as published by the Free Software Foundation.
 *
 *  The GNU Lesser General Public License can be found at
 *  http://www.gnu.org/licenses/lgpl.html.
 *  A copy is found in the textfile LGPL.txt and important notices to the
 *  license from the author are found in LICENSE.txt distributed with
 *  these libraries.
 *
 *  This library 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 General Public License for more details.
 *
 *  For further information about UCS - unique computing solutions gmbh,
 *  please see the company website: http://www.ucs.at
 *
 *  For further information about [fleXive](R), please see the
 *  project website: http://www.flexive.org
 *
 *
 *  This copyright notice MUST APPEAR in all copies of the file!
 ***************************************************************/
package com.flexive.shared.structure;

import com.flexive.shared.*;
import com.flexive.shared.exceptions.FxApplicationException;
import com.flexive.shared.exceptions.FxInvalidParameterException;
import com.flexive.shared.exceptions.FxNotFoundException;
import com.flexive.shared.security.ACL;
import com.flexive.shared.value.FxString;
import com.flexive.shared.value.FxValue;
import org.apache.commons.lang.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * FxPropertyAssignment for editing
 *
 * @author Markus Plesser (markus.plesser@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
 */
public class FxPropertyAssignmentEdit extends FxPropertyAssignment {

    private static final long serialVersionUID = -4124525757694024524L;
    private boolean isNew;

    /**
     * Create an editable instance from an existing FxPropertyAssignment
     *
     * @param pa existing FxPropertyAssignment
     */
    public FxPropertyAssignmentEdit(FxPropertyAssignment pa) {
        super(pa.getId(), pa.isEnabled(), pa.getAssignedType(), pa.getAlias(), pa.getXPath(), pa.getPosition(),
                new FxMultiplicity(pa.getMultiplicity()), pa.getDefaultMultiplicity(),
                pa.getParentGroupAssignment(), pa.getBaseAssignmentId(),
                pa.getLabel() == null ? null : pa.getLabel().copy(),
                pa.getHint() == null ? null : pa.getHint().copy(),
                pa.hasAssignmentDefaultValue() ? pa.getDefaultValue().copy() : null, pa.getProperty().asEditable(),
                new ACL(pa.getACL()), pa.getDefaultLanguage(), FxStructureOption.cloneOptions(pa.options),
                pa.getFlatStorageMapping());
        if (pa.isSystemInternal())
            _setSystemInternal();
        this.isNew = false;
    }

    /**
     * Ctor to create a new FxPropertyAssignmentEdit from an existing FxPropertyAssignment as a new one for a given type with a
     * new alias and a given parentXPath (not validated)
     *
     * @param pa          original property assignment
     * @param type        type to assign it
     * @param alias       new alias
     * @param parentXPath parent XPath within the type to assign
     * @param parent      optional parent assignment if already known (prevents lookup of parentXPath if valid)
     * @throws FxNotFoundException         if parentXPath is invalid
     * @throws FxInvalidParameterException if parentXPath is invalid
     */
    private FxPropertyAssignmentEdit(FxPropertyAssignment pa, FxType type, String alias, String parentXPath,
            FxAssignment parent) throws FxNotFoundException, FxInvalidParameterException {
        super(-1, pa.isEnabled(), type, alias, XPathElement.buildXPath(false, parentXPath, alias), pa.getPosition(),
                new FxMultiplicity(pa.getMultiplicity()), pa.getDefaultMultiplicity(),
                pa.getParentGroupAssignment(), pa.getId(), pa.getLabel().copy(), pa.getHint().copy(),
                pa.hasAssignmentDefaultValue() ? pa.getDefaultValue().copy() : null, pa.getProperty().asEditable(),
                new ACL(pa.getACL()), pa.getDefaultLanguage(), FxStructureOption.cloneOptions(pa.options),
                pa.getFlatStorageMapping());
        if (pa.isSystemInternal())
            _setSystemInternal();
        if (parent == null) {
            //check parentXPath
            parent = type.getAssignment(parentXPath);
            if (parent != null && parent instanceof FxPropertyAssignment)
                throw new FxInvalidParameterException("parentXPath", "ex.structure.assignment.noGroup",
                        parentXPath);
        }
        //check parentXPath
        if (parent == null)
            parentGroupAssignment = null;
        else
            parentGroupAssignment = (FxGroupAssignment) parent;
        this.flatStorageMapping = null;
        isNew = true;
    }

    /**
     * Create a new FxPropertyAssignmentEdit from an existing property for a given type with a
     * new alias and a given parentXPath
     *
     * @param property    the property name
     * @param type        type to assign it
     * @param alias       new alias
     * @param parentXPath parent XPath within the type to assign
     */
    public FxPropertyAssignmentEdit(FxProperty property, FxType type, String alias, String parentXPath) {
        super(-1, true, type, alias, XPathElement.buildXPath(false, parentXPath, alias), 0,
                property.getMultiplicity(), 1, null, FxAssignment.NO_BASE, property.getLabel().copy(),
                property.getHint().copy(), null, property, property.getACL(),
                property.getLabel().getDefaultLanguage(), FxStructureOption.cloneOptions(property.options), null);
        this.flatStorageMapping = null;
        isNew = true;
    }

    public boolean isNew() {
        return isNew;
    }

    /**
     * Clear the default value
     */
    public void clearDefaultValue() {
        this.defaultValue = null;
    }

    public FxPropertyAssignmentEdit setACL(ACL ACL) throws FxInvalidParameterException {
        if (!getProperty().mayOverrideACL())
            throw new FxInvalidParameterException("ACL", "ex.structure.override.property.forbidden", "ACL",
                    getProperty().getName());
        this.ACL = ACL;
        return this;
    }

    /**
     * Set the default value for this property assignment
     *
     * @param defaultValue default value
     * @return this
     */
    @SuppressWarnings({ "ThrowableInstanceNeverThrown" })
    public FxPropertyAssignmentEdit setDefaultValue(FxValue defaultValue) {
        if (defaultValue != null && defaultValue.isMultiLanguage() != this.isMultiLang()) {
            if (defaultValue.isMultiLanguage())
                throw new FxInvalidParameterException("value", "ex.content.value.invalid.multilanguage.prop.single",
                        getXPath()).asRuntimeException();
            else
                throw new FxInvalidParameterException("value", "ex.content.value.invalid.multilanguage.prop.multi",
                        getXPath()).asRuntimeException();
        }
        this.defaultValue = defaultValue;
        return this;
    }

    /**
     * Set an option with defaults of overridable & isInherited == true
     *
     * @param key   option key
     * @param value value of the option
     * @return the assignment itself, useful for chained calls
     * @throws FxInvalidParameterException if the property does not allow overriding
     */
    public FxPropertyAssignmentEdit setOption(String key, String value) throws FxInvalidParameterException {
        return setOption(key, true, true, value);
    }

    /**
     * Set a boolean option with defaults of overridable & isInherited == true
     *
     * @param key   option key
     * @param value value of the option
     * @return the assignemnt itself, useful for chained calls
     * @throws FxInvalidParameterException if the property does not allow overriding
     */
    public FxPropertyAssignmentEdit setOption(String key, boolean value) throws FxInvalidParameterException {
        return setOption(key, true, true, value);
    }

    /**
     * Set an option
     *
     * @param key          the option key
     * @param overridable the overridable status
     * @param isInherited  the isInherited status (inherited by derived assignments)
     * @param value        the option value
     * @return the assignment itself, useful f. chained calls
     * @throws FxInvalidParameterException on errors
     * @since 3.1.1
     */
    public FxPropertyAssignmentEdit setOption(String key, boolean overridable, boolean isInherited, String value)
            throws FxInvalidParameterException {
        // already set in the property?
        FxStructureOption pOpt = getProperty().getOption(key);
        if (pOpt.isSet() && !pOpt.isOverridable())
            throw new FxInvalidParameterException(key, "ex.structure.override.property.forbidden", key,
                    getProperty().getName());

        if (this.isDerivedAssignment()) {
            if (FxSharedUtils.checkAssignmentInherited(this)) {
                FxPropertyAssignment base = (FxPropertyAssignment) CacheAdmin.getEnvironment()
                        .getAssignment(getBaseAssignmentId());
                if (base.getOption(key).getIsInherited() && !base.getOption(key).isOverridable()) {
                    // only complain if the value gets overridden
                    if (!value.equals(base.getOption(key).getValue()))
                        throw new FxInvalidParameterException(key,
                                "ex.structure.override.propertyAssignment.forbidden", key, base.getXPath());
                }
            }
        }

        FxStructureOption.setOption(options, key, overridable, isInherited, value);
        return this;
    }

    /**
     * Set a boolean option
     *
     * @param key          the option key
     * @param overridable overridable status
     * @param isInherited  the isInherited status (inherited by derived assignments)
     * @param value        the option value
     * @return the assignment itself, useful f. chained calls
     * @throws FxInvalidParameterException on errors
     * @since 3.1.1
     */
    public FxPropertyAssignmentEdit setOption(String key, boolean overridable, boolean isInherited, boolean value)
            throws FxInvalidParameterException {
        // already set in the property?
        FxStructureOption pOpt = getProperty().getOption(key);
        if (pOpt.isSet() && !pOpt.isOverridable())
            throw new FxInvalidParameterException(key, "ex.structure.override.property.forbidden", key,
                    getProperty().getName());

        if (this.isDerivedAssignment()) {
            if (FxSharedUtils.checkAssignmentInherited(this)) {
                FxPropertyAssignment base = (FxPropertyAssignment) CacheAdmin.getEnvironment()
                        .getAssignment(getBaseAssignmentId());
                if (base.getOption(key).getIsInherited() && !base.getOption(key).isOverridable()) {
                    // only complain if the value gets overridden
                    final String inValue = value ? FxStructureOption.VALUE_TRUE : FxStructureOption.VALUE_FALSE;
                    if (!inValue.equals(base.getOption(key).getValue()))
                        throw new FxInvalidParameterException(key,
                                "ex.structure.override.propertyAssignment.forbidden", key, base.getXPath());
                }
            }
        }

        FxStructureOption.setOption(options, key, overridable, isInherited, value);
        return this;
    }

    /**
     * Clear an option entry
     *
     * @param key option name
     */
    public void clearOption(String key) {
        FxStructureOption.clearOption(options, key);
    }

    /**
     * Assign options
     *
     * @param options options to assign
     */
    public void setOptions(List<FxStructureOption> options) {
        this.options = options;
    }

    /**
     * Should this assignment support multilingual data?
     *
     * @param multiLang multi lingual data supported?
     * @return this
     * @throws FxInvalidParameterException on errors
     */
    public FxPropertyAssignmentEdit setMultiLang(boolean multiLang) throws FxInvalidParameterException {
        if (!getProperty().mayOverrideMultiLang())
            throw new FxInvalidParameterException("MULTILANG", "ex.structure.override.property.forbidden",
                    "MULTILANG", getProperty().getName());

        return setOption(FxStructureOption.OPTION_MULTILANG, multiLang);
    }

    /**
     * Set a default language. Multilingual FxPropertyData instances will be initialized with this language
     *
     * @param language the default language
     * @return this
     */
    public FxPropertyAssignmentEdit setDefaultLanguage(long language) {
        if (this.isMultiLang())
            this.defaultLang = language;
        return this;
    }

    /**
     * Reset the default language to the system language
     *
     * @return this
     */
    public FxPropertyAssignmentEdit clearDefaultLanguage() {
        if (this.isMultiLang())
            this.defaultLang = FxLanguage.SYSTEM_ID;
        return this;
    }

    /**
     * Set if  this property be used in the visual query editor (UI hint)
     *
     * @param searchable property can be used in the visual query editor
     * @return the property itself, useful for chained calls
     * @throws FxInvalidParameterException if overriding is not allowed
     */
    public FxPropertyAssignmentEdit setSearchable(boolean searchable) throws FxInvalidParameterException {
        if (!getProperty().mayOverrideSearchable())
            throw new FxInvalidParameterException("SEARCHABLE", "ex.structure.override.property.forbidden",
                    "SEARCHABLE", getProperty().getName());
        return setOption(FxStructureOption.OPTION_SEARCHABLE, searchable);
    }

    /**
     * Set overview appearance setting
     *
     * @param inOverview overview appearance setting
     * @return the property itself, useful for chained calls
     * @throws FxInvalidParameterException if not allowed to override
     */
    public FxPropertyAssignmentEdit setInOverview(boolean inOverview) throws FxInvalidParameterException {
        if (!getProperty().mayOverrideInOverview())
            throw new FxInvalidParameterException("INOVERVIEW", "ex.structure.override.property.forbidden",
                    "INOVERVIEW", getProperty().getName());
        return setOption(FxStructureOption.OPTION_SHOW_OVERVIEW, inOverview);
    }

    /**
     * Set if to use an HTML editor to edit values of this property?
     *
     * @param useHTMLEditor use HTML editor to edit values of this property?
     * @return the property itself, useful for chained calls
     * @throws FxInvalidParameterException if not allowed to override
     */
    public FxPropertyAssignmentEdit setUseHTMLEditor(boolean useHTMLEditor) throws FxInvalidParameterException {
        if (!getProperty().mayOverrideUseHTMLEditor())
            throw new FxInvalidParameterException("USEHTMLEDITOR", "ex.structure.override.property.forbidden",
                    "USEHTMLEDITOR", getProperty().getName());
        return setOption(FxStructureOption.OPTION_HTML_EDITOR, useHTMLEditor);
    }

    /**
     * Set multiline display ability
     *
     * @param multiLine render property in multiple lines?
     * @return the property itself, useful for chained calls
     * @throws FxInvalidParameterException on errors
     */
    public FxPropertyAssignmentEdit setMultiLine(boolean multiLine) throws FxInvalidParameterException {
        if (!getProperty().mayOverrideMultiLine())
            throw new FxInvalidParameterException("MULTILINE", "ex.structure.override.property.forbidden",
                    "MULTILINE", getProperty().getName());
        return setOption(FxStructureOption.OPTION_MULTILINE, multiLine);
    }

    /**
     * Shortcut to set the maximum input length (if applicable to the component)
     *
     * @param maxLength desired maximum input length
     * @return the property itself, useful for chained calls
     * @throws FxInvalidParameterException on errors
     */
    public FxPropertyAssignmentEdit setMaxLength(int maxLength) throws FxInvalidParameterException {
        if (!getProperty().mayOverrideMaxLength())
            throw new FxInvalidParameterException("MAXLENGTH", "ex.structure.override.property.forbidden",
                    "MAXLENGTH", getProperty().getName());
        return setOption(FxStructureOption.OPTION_MAXLENGTH, String.valueOf(maxLength));
    }

    /**
     * Set this property assignment as (temporary) disabled - it will not be initialized when creating new instances, etc.
     *
     * @param enabled enabled flag
     * @return this
     */
    public FxPropertyAssignmentEdit setEnabled(boolean enabled) {
        this.enabled = enabled;
        return this;
    }

    /**
     * Set the multiplicity of this assignment
     *
     * @param multiplicity new multiplicity
     * @return this
     * @throws FxInvalidParameterException on errors
     */
    public FxPropertyAssignmentEdit setMultiplicity(FxMultiplicity multiplicity)
            throws FxInvalidParameterException {
        if (!getProperty().mayOverrideBaseMultiplicity())
            throw new FxInvalidParameterException("MULTIPLICITY", "ex.structure.override.property.forbidden",
                    "Multiplicity", getProperty().getName());
        this.multiplicity = multiplicity;
        return this;
    }

    /**
     * Set the default multiplicity (used i.e. in user interfaces editors and determines the amount of values that will
     * be initialized when creating an empty element).
     *
     * @param defaultMultiplicity the default multiplicity
     * @return this
     * @throws com.flexive.shared.exceptions.FxInvalidParameterException
     *          if the defaultMultiplicity is not within the range of min and max
     */
    public FxPropertyAssignmentEdit setDefaultMultiplicity(int defaultMultiplicity)
            throws FxInvalidParameterException {
        super.defaultMultCalc = -1; //reset cached value
        if (this.getMultiplicity().isValid(defaultMultiplicity)) {
            this.defaultMultiplicity = defaultMultiplicity;
            return this;
        }
        if (defaultMultiplicity < this.getMultiplicity().getMin())
            this.defaultMultiplicity = this.getMultiplicity().getMin();
        if (defaultMultiplicity > this.getMultiplicity().getMax())
            this.defaultMultiplicity = this.getMultiplicity().getMax();
        return this;
    }

    /**
     * Set the position of this assignment (within the same parent group).
     * Changing an assignments position will be upate all affected other assignments within the same
     * group. Invalid values will be adjusted (to 0 or the max. possible position)
     *
     * @param position position within the parent group
     * @return this
     */
    public FxPropertyAssignmentEdit setPosition(int position) {
        this.position = position;
        return this;
    }

    /**
     * Set the alias of this property assignment.
     * Property assignments may define an alias to allow multiple use of the same property but
     * using a different name. The alias is the rightmost part of the XPath used to address an assignment.
     * Will affect the XPath as well.
     *
     * @param alias the alias of this assignment
     * @return this
     * @throws FxInvalidParameterException on errors
     */
    public FxPropertyAssignmentEdit setAlias(String alias) throws FxInvalidParameterException {
        if (StringUtils.isEmpty(alias))
            throw new FxInvalidParameterException("ALIAS", "ex.structure.assignment.noAlias");
        //only react to alias changes
        if (!this.alias.trim().toUpperCase().equals(alias.trim().toUpperCase())) {
            this.alias = alias.trim().toUpperCase();
            List<XPathElement> xpe = XPathElement.splitNew(this.XPath);
            xpe.set(xpe.size() - 1, new XPathElement(this.alias, 1, true));
            this.XPath = XPathElement.toXPathNoMult(xpe);
        }
        return this;
    }

    /**
     * Set the XPath of this assignment - this is used mainly internally and affects new assignments only
     *
     * @param XPath the XPath to set
     * @return this
     * @throws FxInvalidParameterException on errors
     */
    public FxPropertyAssignmentEdit setXPath(String XPath) throws FxInvalidParameterException {
        if (StringUtils.isEmpty(alias))
            throw new FxInvalidParameterException("XPATH", "ex.structure.assignment.noXPath");
        if (this.getAssignedType().isXPathValid(XPath, true))
            throw new FxInvalidParameterException("XPATH", "ex.structure.assignment.exists", XPath,
                    getAssignedType().getName());
        this.XPath = XPath;
        return this;
    }

    /**
     * Setter for the label
     *
     * @param label label to set
     * @return this
     */
    public FxPropertyAssignmentEdit setLabel(FxString label) {
        this.label = label;
        return this;
    }

    /**
     * Set the hint message
     *
     * @param hint hint message
     * @return the property itself, useful for chained calls
     */
    public FxPropertyAssignmentEdit setHint(FxString hint) {
        this.hint = hint;
        return this;
    }

    /**
     * Create a new FxPropertyAssignmentEdit from an existing FxPropertyAssignment as a new one for a given type with a
     * new alias and a given parentXPath
     *
     * @param pa          original property assignment
     * @param type        type to assign it
     * @param alias       new alias
     * @param parentXPath parent XPath within the type to assign
     * @param parent      optional parent assignment if already known (prevents lookup of parentXPath if valid)
     * @return new FxPropertyAssignmentEdit
     * @throws FxNotFoundException         if parentXPath is invalid
     * @throws FxInvalidParameterException if parentXPath is invalid
     */
    public static FxPropertyAssignmentEdit createNew(FxPropertyAssignment pa, FxType type, String alias,
            String parentXPath, FxAssignment parent) throws FxNotFoundException, FxInvalidParameterException {
        return new FxPropertyAssignmentEdit(pa, type, alias, parentXPath, parent);
    }

    /**
     * Create a new FxPropertyAssignmentEdit from an existing FxPropertyAssignment as a new one for a given type with a
     * new alias and a given parentXPath
     *
     * @param pa          original property assignment
     * @param type        type to assign it
     * @param alias       new alias
     * @param parentXPath parent XPath within the type to assign
     * @return new FxPropertyAssignmentEdit
     * @throws FxNotFoundException         if parentXPath is invalid
     * @throws FxInvalidParameterException if parentXPath is invalid
     */
    public static FxPropertyAssignmentEdit createNew(FxPropertyAssignment pa, FxType type, String alias,
            String parentXPath) throws FxNotFoundException, FxInvalidParameterException {
        return new FxPropertyAssignmentEdit(pa, type, alias, parentXPath, null);
    }

    /**
     * Create a new FxPropertyAssignmentEdit from an existing property for a given type with a
     * new alias and a given parentXPath
     *
     * @param property    the property name
     * @param type        type to assign it
     * @param alias       new alias
     * @param parentXPath parent XPath within the type to assign
     * @return new FxPropertyAssignmentEdit
     * @throws FxNotFoundException         if parentXPath is invalid
     * @throws FxInvalidParameterException if parentXPath is invalid
     */
    public static FxPropertyAssignmentEdit createNew(String property, FxType type, String alias, String parentXPath)
            throws FxNotFoundException, FxInvalidParameterException {
        return new FxPropertyAssignmentEdit(CacheAdmin.getEnvironment().getProperty(property), type, alias,
                parentXPath);
    }

    /**
     * Convenience method to create a new FxPropertyAssignmentEdit from an existing FxPropertyAssignment as a new one for a given type with a
     * new alias and a given parentXPath
     *
     * @param originalAssignment the original assignments XPath (like ROOT/CAPTION)
     * @param type               name of the type to assign it
     * @param parentXPath        parent XPath within the type to assign
     * @param alias              new alias
     * @return new FxPropertyAssignmentEdit
     * @throws FxNotFoundException         if parentXPath is invalid
     * @throws FxInvalidParameterException if parentXPath is invalid
     */
    public static FxPropertyAssignmentEdit reuse(String originalAssignment, String type, String parentXPath,
            String alias) throws FxNotFoundException, FxInvalidParameterException {
        return createNew((FxPropertyAssignment) CacheAdmin.getEnvironment().getAssignment(originalAssignment),
                CacheAdmin.getEnvironment().getType(type), alias, parentXPath).setEnabled(true);
    }

    /**
     * Convenience method to create a new FxPropertyAssignmentEdit from an existing FxPropertyAssignment as a new one for a given type with a
     * new alias and a given parentXPath
     *
     * @param originalAssignment the original assignments XPath (like ROOT/CAPTION)
     * @param type               name of the type to assign it
     * @param parentXPath        parent XPath within the type to assign
     * @return new FxPropertyAssignmentEdit
     * @throws FxNotFoundException         if parentXPath is invalid
     * @throws FxInvalidParameterException if parentXPath is invalid
     */
    public static FxPropertyAssignmentEdit reuse(String originalAssignment, String type, String parentXPath)
            throws FxNotFoundException, FxInvalidParameterException {
        FxPropertyAssignment propertyAssignment = (FxPropertyAssignment) CacheAdmin.getEnvironment()
                .getAssignment(originalAssignment);
        return createNew(propertyAssignment, CacheAdmin.getEnvironment().getType(type),
                propertyAssignment.getAlias(), parentXPath).setEnabled(true);
    }

    /**
     * Sets the parent group assignment.
     *
     * @param parent the parent group assignment.
     */
    public void setParentGroupAssignment(FxGroupAssignment parent) {
        this.parentGroupAssignment = parent;
    }

    /**
     * Returns the property of this assignment as editable.
     *
     * @return the editable property object.
     */
    public FxPropertyEdit getPropertyEdit() {
        if (!(property instanceof FxPropertyEdit))
            //noinspection ThrowableInstanceNeverThrown
            throw new FxApplicationException("ex.structure.noEditableProperty").asRuntimeException();
        else
            return (FxPropertyEdit) property;
    }

    /**
     * Save this assignment and return the saved instance.
     *
     * @return  the saved assignment
     * @throws FxApplicationException on errors
     *
     * @since 3.1
     */
    public FxPropertyAssignmentEdit save() throws FxApplicationException {
        final long id = EJBLookup.getAssignmentEngine().save(this, false);
        return CacheAdmin.getEnvironment().getPropertyAssignment(id).asEditable();
    }

    /**
     * Returns a new List of all available options.
     * The options include those of the class itsself and of its assigned FxProperty
     * To eliminate duplicate keys and determine the correct overriding oder,
     * the <code>FxPropertyAssignment.getOption(key)</code> method
     * is used. If an option is contained in the returned List then <code>hasOption(key)
     * ==true</code>, otherwise <code>false</code>.
     *
     * @return new List containing all availiable options.
     */
    protected List<FxStructureOption> getAllAvailableOptions() {
        List<FxStructureOption> allOptions = new ArrayList<FxStructureOption>(options);
        List<String> setOptions = new ArrayList<String>(2);
        List<FxStructureOption> result = new ArrayList<FxStructureOption>();

        allOptions.addAll(super.getProperty().options);
        allOptions.addAll(options);
        //iterate over all options and eliminate duplicate keys
        for (FxStructureOption o : allOptions) {
            if (hasOption(o.getKey())) {
                if (!setOptions.contains(o.getKey())) {
                    setOptions.add(o.getKey());
                    result.add(getOption(o.getKey()));
                }
            }
        }
        return result;
    }

}