/* * Copyright (c) 2009-2010 Lockheed Martin Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.eurekastreams.server.domain; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.PostLoad; import javax.persistence.PrePersist; import javax.persistence.Transient; import org.eurekastreams.commons.model.DomainEntity; /** * This class provides the model for supporting OpenSocial Application Data. * */ @SuppressWarnings("serial") @Entity public class AppData extends DomainEntity implements Serializable { /** * List of the AppData values that are associated with the Gadget and * Person. */ @OneToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL }) @JoinColumn(name = "appDataId") private List<AppDataValue> appDataValues = new ArrayList<AppDataValue>(); /** * This is many to one because there is no sense in using a gadget to get * all of the application data because it could contain 1000's of entries. * This is takeaway from the Shindig db implementation example. */ @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "gadgetDefinitionId") private GadgetDefinition gadgetDefinition; /** * This is the reference to the person that is associated with this app * data. */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "personId") private Person person; /** * Local map that will be exposed to the client. Used for better * manipulation of data and what the interfaces require. */ @Transient private Map<String, String> values = new HashMap<String, String>(); /** * Default constructor. */ public AppData() { // Empty Constructor. } /** * Constructor that inputs Person and GadgetDefinition Objects. * * @param inPerson * - instance of person to associate app data with. * @param inGadgetDefinition * - instance of gadgetdefinition to associate app data with. */ public AppData(final Person inPerson, final GadgetDefinition inGadgetDefinition) { gadgetDefinition = inGadgetDefinition; person = inPerson; } /** * Getter for the List of AppDataValues. * * @return List of App Data Values associated with this instance. */ @SuppressWarnings("unused") private List<AppDataValue> getAppDataValues() { return appDataValues; } /** * Setter for the List of AppDataValues. * * @param inValues * input List. */ @SuppressWarnings("unused") private void setAppDataValues(final List<AppDataValue> inValues) { appDataValues = inValues; } /** * Retrieve the gadget instance associated with this AppData instance. * * @return gadget that this AppData is associated with. */ public final GadgetDefinition getGadgetDefinition() { return gadgetDefinition; } /** * Set the gadget instance associated with this AppData instance. * * @param inGadgetDefinition * the Gadget that is associated with this AppData. */ public void setGadgetDefinition(final GadgetDefinition inGadgetDefinition) { this.gadgetDefinition = inGadgetDefinition; } /** * Get the person associated wit this AppData instance. * * @return person that this AppData is associated with. */ public Person getPerson() { return this.person; } /** * Set the person associated with this AppData instance. * * @param inPerson * the Person that is associated with this AppData. */ public void setPerson(final Person inPerson) { this.person = inPerson; } /** * Get the Map of Values for this AppData instance. * * @return Map of key and value for this AppData instance. */ public Map<String, String> getValues() { return Collections.unmodifiableMap(this.values); } /** * Set the Map of Values for this AppData instance. * * @param inValues * Map of values. */ public void setValues(final Map<String, String> inValues) { this.values = inValues; prePersist(); } /** * This method is performed before the data is persisted to the database. * The concepts and logic were taken from samples in the Shindig project. * The idea behind this method is to convert the Map String, String exposed * to the caller back into the persisted structure of List AppDataValue. */ @PrePersist public void prePersist() { // check for new items (in values but not in appDataValues) for (Entry<String, String> currentEntry : values.entrySet()) { AppDataValue currentValue = findValueByKey(appDataValues, currentEntry.getKey()); // If we have a new entry if (currentValue == null) { currentValue = new AppDataValue(currentEntry.getKey(), currentEntry.getValue(), this); appDataValues.add(currentValue); } else { currentValue.setValue(currentEntry.getValue()); } } // check for ones to be deleted (in appDataValues but not in values) List<String> toRemove = new ArrayList<String>(); for (AppDataValue currentAppDataEntry : appDataValues) { // If the current map of keys and values doesn't contain the current // entry's key, then it has been removed and don't persist it. if (!values.containsKey(currentAppDataEntry.getName())) { toRemove.add(currentAppDataEntry.getName()); } } // Remove those keys identified to be deleted. for (String keyToRemove : toRemove) { appDataValues.remove(findValueByKey(appDataValues, keyToRemove)); } } /** * This method occurs directly following the load of the data from the db. * This converts the List AppDataValues into a Map String, String that is * easier for a caller to consume. */ @PostLoad public void postLoad() { for (AppDataValue currentEntry : appDataValues) { values.put(currentEntry.getName(), currentEntry.getValue()); } } /** * Helper method to find data in the persisted List of AppDataValues. * * @param loadedValues * - database loaded AppDataValues * @param key * - key to find in the list of AppDataValues. * @return null if not found and the AppDataValue object if found. */ private AppDataValue findValueByKey(final List<AppDataValue> loadedValues, final String key) { if (loadedValues != null) { for (AppDataValue currentValue : loadedValues) { if (currentValue.getName() == key) { return currentValue; } } } return null; } }