MultiSelectionDataField.java :  » ERP-CRM-Financial » JFire-1.0.1 » org » nightlabs » jfire » prop » datafield » Java Open Source

Java Open Source » ERP CRM Financial » JFire 1.0.1 
JFire 1.0.1 » org » nightlabs » jfire » prop » datafield » MultiSelectionDataField.java
/* *****************************************************************************
 * JFire - it's hot - Free ERP System - http://jfire.org                       *
 * Copyright (C) 2004-2005 NightLabs - http://NightLabs.org                    *
 *                                                                             *
 * This library 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.          *
 *                                                                             *
 * 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           *
 * 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 St, Fifth Floor,                                            *
 *     Boston, MA  02110-1301  USA                                             *
 *                                                                             *
 * Or get it online :                                                          *
 *     http://opensource.org/licenses/lgpl-license.php                         *
 *                                                                             *
 *                                                                             *
 ******************************************************************************/

package org.nightlabs.jfire.prop.datafield;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.annotations.FetchGroup;
import javax.jdo.annotations.FetchGroups;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.Inheritance;
import javax.jdo.annotations.InheritanceStrategy;
import javax.jdo.annotations.Join;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.PersistenceModifier;
import javax.jdo.annotations.Persistent;
import javax.jdo.listener.DetachCallback;

import org.nightlabs.i18n.I18nTextBuffer;
import org.nightlabs.jfire.prop.DataBlock;
import org.nightlabs.jfire.prop.DataField;
import org.nightlabs.jfire.prop.PropertySet;
import org.nightlabs.jfire.prop.StructField;
import org.nightlabs.jfire.prop.id.MultiSelectionStructFieldValueID;
import org.nightlabs.jfire.prop.structfield.MultiSelectionStructField;
import org.nightlabs.jfire.prop.structfield.MultiSelectionStructFieldValue;
import org.nightlabs.jfire.prop.structfield.StructFieldValue;

/**
 * {@link DataField} that holds one member of type {@link MultiSelectionStructFieldValue} defining the users
 * choice from the list within {@link MultiSelectionStructField}.
 *
 * @author Marc Klinger - marc[at]nightlabs[dot]de
 * @author Alexander Bieber <!-- alex [AT] nightlabs [DOT] de --> (Original SectionDataField code)
 */
@PersistenceCapable(
  identityType=IdentityType.APPLICATION,
  detachable="true",
  table="JFireBase_Prop_MultiSelectionDataField")
@FetchGroups(
  @FetchGroup(
    fetchGroups={"default"},
    name="FetchGroupsProp.fullData",
    members={@Persistent(name="structFieldValueIDs"), @Persistent(name="structFieldValueIDs_correct")})
)
@Inheritance(strategy=InheritanceStrategy.NEW_TABLE)
public class MultiSelectionDataField
extends DataField
implements DetachCallback, II18nTextDataField
{
  /**
   * The serial version of this class.
   */
  private static final long serialVersionUID = 20100202L;

  /**
   * @deprecated This field is persisted as BLOB! I introduced {@link #structFieldValueIDs_correct} in order to fix this bug.
   */
  @Deprecated
  @Persistent
  protected Set<String> structFieldValueIDs;

  @Persistent(
      table="JFireBase_Prop_MultiSelectionDataField_structFieldValueIDs"
  )
  @Join
  protected Set<String> structFieldValueIDs_correct;

  @Persistent(persistenceModifier=PersistenceModifier.NONE)
  private transient I18nTextBuffer textBuffer = null;

  @Persistent(persistenceModifier=PersistenceModifier.NONE)
  protected Set<MultiSelectionStructFieldValue> structFieldValues;

  /**
   * For JDO only.
   */
  protected MultiSelectionDataField()
  {
    super();
  }

  /**
   * Create a new {@link MultiSelectionDataField} for the given {@link DataBlock}
   * that represents the given {@link StructField}.
   *
   * @param dataBlock The {@link DataBlock} the new {@link MultiSelectionDataField} will be part of.
   * @param structField The {@link StructField} the new {@link MultiSelectionDataField} represents in the data structure.
   */
  public MultiSelectionDataField(DataBlock dataBlock, StructField<MultiSelectionDataField> structField)
  {
    super(dataBlock, structField);
    structFieldValueIDs_correct = new HashSet<String>();
  }

  /**
   * Used for cloning.
   */
  protected MultiSelectionDataField(String organisationID, long propertySetID, MultiSelectionDataField cloneField)
  {
    super(organisationID, propertySetID, cloneField);
    structFieldValueIDs_correct = new HashSet<String>();
  }
  /**
   * Set the {@link MultiSelectionStructFieldValue} selected for this {@link MultiSelectionDataField}.
   * Note, that only the {@link StructFieldValue#getStructFieldValueID()}
   * is stored in this data field.
   *
   * @param values The selection to set.
   */
  public void setSelection(MultiSelectionStructFieldValue values)
  {
    setSelection(Collections.singleton(values));
  }

  /**
   * Set the {@link MultiSelectionStructFieldValue} selected for this {@link MultiSelectionDataField}.
   * Note, that only the {@link MultiSelectionStructFieldValue#getStructFieldValueID()}
   * is stored in this data field.
   *
   * @param values The selection to set.
   */
  public void setSelection(Collection<MultiSelectionStructFieldValue> values)
  {
    structFieldValueIDs = null;

    if (values == null || values.isEmpty()) {
      structFieldValueIDs_correct.clear();
      structFieldValues = null;
    }
    else {
      structFieldValueIDs_correct.clear();
      for (MultiSelectionStructFieldValue structFieldValue : values)
        structFieldValueIDs_correct.add(structFieldValue.getStructFieldValueID());
      // XXX: add hashCode() and equals() to StructFieldValue
      structFieldValues = new HashSet<MultiSelectionStructFieldValue>(values);
    }
    resetTextBuffer();
  }

  /**
   * Returns the {@link StructFieldValue#getStructFieldValueID()}s of the selected
   * {@link MultiSelectionStructFieldValue}s selected for this {@link MultiSelectionDataField}.
   * The {@link MultiSelectionStructFieldValue}s corresponding to the selection can be
   * retrieved using {@link #getStructFieldValues()}.
   *
   * @return The structFieldValueID of the selected {@link StructFieldValue}.
   */
  public Set<String> getStructFieldValueIDs()
  {
    if (structFieldValueIDs != null)
      return structFieldValueIDs;

    return Collections.unmodifiableSet(structFieldValueIDs_correct);
  }

  /**
   * Returns the selected {@link MultiSelectionStructFieldValue}s of this MultiSelectionStructField.
   * <p>
   * If this is called on a persistent instance the value is resolved from datastore.
   * </p>
   * <p>
   * If this is called on a detached instance the value must have been resolved during
   * the detach process. This will be done if the fetch plan contains {@link PropertySet#FETCH_GROUP_FULL_DATA}.
   * (see {@link #jdoPostDetach(Object)}).
   * </p>
   * @return The selected {@link MultiSelectionStructFieldValue} of this MultiSelectionStructField.
   */
  public Collection<MultiSelectionStructFieldValue> getStructFieldValues()
  {
    if (JDOHelper.isPersistent(this))
      return resolveStructFieldValue(JDOHelper.getPersistenceManager(this), this);

    if (structFieldValues == null)
      structFieldValues = new HashSet<MultiSelectionStructFieldValue>();

    return Collections.unmodifiableSet(structFieldValues);
  }

//  public MultiSelectionStructField getSelectionStructField(IStruct structure) throws ClassCastException
//  {
//    IllegalStateException ill = null;
//    MultiSelectionStructField field = null;
//    try
//    {
//      field = (MultiSelectionStructField) structure.getStructField(getStructBlockOrganisationID(), getStructBlockID(),
//          getStructFieldOrganisationID(), getStructFieldID());
//    }
//    catch (Exception e)
//    {
//      ill = new IllegalStateException("Caught exception while accessing PropStructFactory");
//      ill.initCause(e);
//    }
//    if (ill != null)
//      throw ill;
//    return field;
//  }

  /* (non-Javadoc)
   * @see org.nightlabs.jfire.prop.DataField#getStructField()
   */
  @Override
  public MultiSelectionStructField getStructField()
  {
    return (MultiSelectionStructField) super.getStructField();
  }

  /* (non-Javadoc)
   * @see org.nightlabs.jfire.prop.DataField#isEmpty()
   */
  @Override
  public boolean isEmpty()
  {
    if (getStructField() == null)
      throw new IllegalStateException("isEmpty() was called on deflated data field.");

    return (getStructFieldValueIDs() == null || getStructFieldValueIDs().isEmpty()) &&
           (getStructField().getDefaultValues() == null || getStructField().getDefaultValues().isEmpty());
  }

  /* (non-Javadoc)
   * @see org.nightlabs.jfire.prop.DataField#cloneDataField(org.nightlabs.jfire.prop.PropertySet)
   */
  @Override
  public DataField cloneDataField(PropertySet propertySet)
  {
    MultiSelectionDataField newField = new MultiSelectionDataField(getOrganisationID(), propertySet.getPropertySetID(), this);
    newField.structFieldValueIDs_correct = new HashSet<String>(this.getStructFieldValueIDs());
    return newField;
  }

  private void resetTextBuffer()
  {
    textBuffer = null;
  }

  /**
   * Create a i18n text containing a coma seperated list of text for
   * every language available.
   */
  private void updateTextBuffer()
  {
    textBuffer = new I18nTextBuffer();
    Collection<MultiSelectionStructFieldValue> structFieldValues = getStructFieldValues();
    if(structFieldValues == null) {
      // do nothing
    }
    else if(structFieldValues.size() == 1) {
      textBuffer.copyFrom(structFieldValues.iterator().next().getValueName());
    }
    else {
      // create a comma separated string containing all names for all languages
      Set<String> languages = new HashSet<String>();
      for(MultiSelectionStructFieldValue value : structFieldValues)
        languages.addAll(value.getValueName().getLanguageIDs());
      for (String language : languages) {
        StringBuilder textInLanguage = new StringBuilder();
        for(MultiSelectionStructFieldValue value : structFieldValues) {
          if(textInLanguage.length() > 0)
            textInLanguage.append(", ");
          String valueNameInLanguage = value.getValueName().getText(language);
          textInLanguage.append(valueNameInLanguage);
        }
        textBuffer.setText(language, textInLanguage.toString());
      }
    }
  }

  /* (non-Javadoc)
   * @see org.nightlabs.jfire.prop.datafield.II18nTextDataField#getI18nText()
   */
  @Override
  public I18nTextBuffer getI18nText()
  {
    if (textBuffer == null)
      updateTextBuffer();
    return textBuffer;
  }

  /**
   * In the post detach callback the {@link MultiSelectionDataField} will check whether
   * {@link PropertySet#FETCH_GROUP_FULL_DATA} is in the fetchplan and resolve the
   * {@link MultiSelectionStructFieldValue}s that are selected for this field. It will then detach
   * the values and set the non-persistent member structFieldValues (see {@link #getStructFieldValues()}).
   */
  @Override
  @SuppressWarnings("unchecked")
  public void jdoPostDetach(Object detached)
  {
    MultiSelectionDataField attached = (MultiSelectionDataField) detached;
    PersistenceManager pm = JDOHelper.getPersistenceManager(attached);
    if (pm.getFetchPlan().getGroups().contains(PropertySet.FETCH_GROUP_FULL_DATA)) {
      Set<MultiSelectionStructFieldValueID> structFieldValueIDs = getStructFieldValueIDs(attached);
      if(structFieldValueIDs != null && !structFieldValueIDs.isEmpty()) {
        // this is a set of String, but we don't need the type information here - so we need no cast
        Set<?> oldFetchGroups = pm.getFetchPlan().getGroups();
        int oldFetchDepth = pm.getFetchPlan().getMaxFetchDepth();
        try {
          this.structFieldValues = new HashSet<MultiSelectionStructFieldValue>(pm.detachCopyAll(pm.getObjectsById(structFieldValueIDs)));
        } finally {
          pm.getFetchPlan().setGroups(oldFetchGroups);
          pm.getFetchPlan().setMaxFetchDepth(oldFetchDepth);
        }
      }
    }
  }

  /*
   * (non-Javadoc)
   * @see javax.jdo.listener.DetachCallback#jdoPreDetach()
   */
  @Override
  public void jdoPreDetach() {
  }

  /**
   * Resolves the {@link MultiSelectionStructFieldValue}s that are selected by the given dataField.
   *
   * @param pm The PersistenceManager to use.
   * @param dataField The {@link MultiSelectionDataField} to resolve the selection for.
   * @return The {@link MultiSelectionStructFieldValue} that is selected by the given dataField.
   */
  @SuppressWarnings("unchecked")
  public static Collection<MultiSelectionStructFieldValue> resolveStructFieldValue(PersistenceManager pm, MultiSelectionDataField dataField)
  {
    Set<MultiSelectionStructFieldValueID> structFieldValueIDs = getStructFieldValueIDs(dataField);
    if(structFieldValueIDs == null || structFieldValueIDs.isEmpty())
      return null;
    return pm.getObjectsById(structFieldValueIDs);
  }

  private static Set<MultiSelectionStructFieldValueID> getStructFieldValueIDs(MultiSelectionDataField dataField)
  {
    Set<String> structFieldValueIDs = dataField.getStructFieldValueIDs();
    if (structFieldValueIDs == null || structFieldValueIDs.isEmpty())
      return Collections.emptySet();
    Set<MultiSelectionStructFieldValueID> result = new HashSet<MultiSelectionStructFieldValueID>(structFieldValueIDs.size());
    for(String structFieldValueId : structFieldValueIDs) {
      result.add(MultiSelectionStructFieldValueID.create(
          dataField.getStructBlockOrganisationID(), dataField.getStructBlockID(),
          dataField.getStructFieldOrganisationID(), dataField.getStructFieldID(),
          structFieldValueId));
    }
    return result;
  }

  /**
   * {@inheritDoc}
   * <p>
   * This is equal to calling {@link #getStructFieldValues()}.
   * </p>
   */
  @Override
  public Object getData()
  {
    return getStructFieldValues();
  }

  /* (non-Javadoc)
   * @see org.nightlabs.jfire.prop.IDataField#setData(java.lang.Object)
   */
  @Override
  @SuppressWarnings("unchecked")
  public void setData(Object data)
  {
    if (data == null) {
      setSelection((Collection<MultiSelectionStructFieldValue>)null);
    } else if (data instanceof MultiSelectionStructFieldValue) {
      setSelection((MultiSelectionStructFieldValue) data);
    } else if (data instanceof Collection<?>) {
      // XXX is this ok?
      setSelection((Collection<MultiSelectionStructFieldValue>) data);
    } else if (data instanceof MultiSelectionDataField) {
      this.structFieldValueIDs = null;
      this.structFieldValueIDs_correct.clear();
      this.structFieldValueIDs_correct.addAll(
          ((MultiSelectionDataField) data).getStructFieldValueIDs()
      );
      this.structFieldValues = ((MultiSelectionDataField) data).structFieldValues;
      // XXX what about the field structFieldValues ???
    }
    resetTextBuffer();
  }

  /* (non-Javadoc)
   * @see org.nightlabs.jfire.prop.IDataField#supportsInputType(java.lang.Class)
   */
  @Override
  public boolean supportsInputType(Class<?> inputType)
  {
    return
      MultiSelectionStructFieldValueID.class.isAssignableFrom(inputType) ||
      // XXX is this ok?
      Collection.class.isAssignableFrom(inputType) ||
      MultiSelectionDataField.class.isAssignableFrom(inputType);
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.