Java tutorial
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can obtain * a copy of the License at https://socialsite.dev.java.net/legal/CDDL+GPL.html * or legal/LICENSE.txt. See the License for the specific language governing * permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at legal/LICENSE.txt. Sun designates this * particular file as subject to the "Classpath" exception as provided by Sun * in the GPL Version 2 section of the License file that accompanied this code. * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * Contributor(s): * * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package com.sun.socialsite.pojos; import com.sun.socialsite.SocialSiteException; import com.sun.socialsite.util.TextUtil; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Stack; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamReader; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; /** * <p>Defines the SocialSite personal Profile properties. * Properties are organized into Display Groups. * A Display Group can have Properties, Property Objects and Collections. * Property Object is an object that has Properties, PropertyObjects and Collections. * A Collection is a collection of objects that have Properties, PropertyObjects and Collections. * Properties, PropertyObject and Collection names are mapped to the OpenSocial Person model.</p> * * <h2>Property naming system</h2> * * <p>Here's some rough EBNF for a full property name:</p> * * <pre> * fullpropertypath ::= sectionname, "_", propertypath * propertypath ::= [pathpart], { "_", [pathpart] }, propertyname * pathpart ::= objectname | collectionspec * collectionspec ::= collectionname, "_", indexnumber * </pre> * * <p>Here's some rough EBNF for a full property object name:</p> * * <pre> * fullpropertyobjectpath ::= sectionname, "_", objectpath * objectpath ::= [pathpart], { "_", [pathpart] }, objectname * pathpart ::= objectname | collectionspec * collectionspec ::= collectionname, "_", indexnumber * </pre> * * <p>Here's some rough EBNF for a full collection object name:</p> * * <pre> * fullcollcetionobjectpath ::= sectionname, "_", collectionobjectpath * collectionobjectpath ::= [pathpart], { "_", [pathpart] }, collectionspec * pathpart ::= objectname | collectionspec * collectionspec ::= collectionname, "_", indexnumber * </pre> * * <h2>Property Definition format</h2> * * <p>Here's a RELAX-NG schema (not verified) for the XML format that SocialSite uses * to specify personal profile properties:</p> * * <pre> * propertyContent = { * attribute name { text }, * attribute namekey { text }, * attribute type { "string" | "text" | "integer" | "datetime" | "boolean" }, * attribute default-value { text }?, * element allowed-values { * element value { text }* * }? * } * objectContent = { * attribute name { text }, * attribute namekey { text }, * element property { propertyContent }*, * element object { objectContent }* * element collection { collectionContent }* * } * collectionContent = { * attribute name { text }, * attribute namekey { text }, * element property { propertyContent }*, * element object { objectContent }* * element collection { collectionContent }* * } * start = element profile { * element display-section { * attribute name { text }, * attribute namekey { text }, * element property { propertyContent }*, * element object { objectContent }*, * element collection { collectionContent }* * }* * } * </pre> * * <h2>Profile privacy settings</h2> * * <p>Each property has visibility settings, because we may need settings there * for some use cases and/or performance, but currently visibility is controlled * at the section level. We'll store a property for each section, with the * name of {section}.visibility and the visibility of the property will * determine the visibility of the section.</p> */ public abstract class PropDefinition { private static Log log = LogFactory.getLog(PropertyDefinition.class); /** Display sections, each has property defs */ private Map<String, DisplaySectionDefinition> sectionDefs = new LinkedHashMap<String, DisplaySectionDefinition>(); /** All properties defs in map form */ private Map<String, PropertyDefinition> propertyDefs = new LinkedHashMap<String, PropertyDefinition>(); /** All properties object defs in map form */ private Map<String, PropertyObjectDefinition> propertyObjectDefs = new LinkedHashMap<String, PropertyObjectDefinition>(); /** All properties object collection defs in map form */ private Map<String, PropertyObjectCollectionDefinition> propertyObjectCollectionDefs = new LinkedHashMap<String, PropertyObjectCollectionDefinition>(); protected PropDefinition() { }; // public PropDefinition(PropDefinition propDef, String defFile) throws SocialSiteException { // init(propDef, getClass().getResourceAsStream(defFile)); // init(this, getClass().getResourceAsStream("/profiledefs.xml")); // } public Collection<DisplaySectionDefinition> getDisplaySectionDefinitions() { return sectionDefs.values(); } public Collection<PropertyDefinition> getPropertyDefinitions() { return propertyDefs.values(); } public Collection<PropertyObjectDefinition> getPropertyObjectDefinitions() { return propertyObjectDefs.values(); } public Collection<PropertyObjectCollectionDefinition> getPropertyObjectCollectionDefinitions() { return propertyObjectCollectionDefs.values(); } /** Gets property definiton for a property specified by name */ public PropertyObjectDefinition getPropertyObjectDefinition(String name) { return propertyObjectDefs.get(name); } /** Gets property definiton for a property specified by name */ public PropertyObjectCollectionDefinition getPropertyObjectCollectionDefinition(String name) { return propertyObjectCollectionDefs.get(name); } public String getId() { return "dummy"; } public abstract static class PropertyDefinitionHolder { private String namekey = null; // I18N name key of property private String path = null; // path to property private String shortName = null; // short name of property private List<PropertyDefinition> properties = new ArrayList<PropertyDefinition>(); private List<PropertyObjectDefinition> propertyObjects = new ArrayList<PropertyObjectDefinition>(); private List<PropertyObjectCollectionDefinition> propertyObjectCollections = new ArrayList<PropertyObjectCollectionDefinition>(); public PropertyDefinitionHolder(String path, String shortName, String namekey) { this.path = path; this.shortName = shortName; this.namekey = namekey; } public abstract String getBasePath(); public String getName() { return path + "_" + shortName; } public String getShortName() { return shortName; } public String getNamekey() { return namekey; } public List<PropertyDefinition> getPropertyDefinitions() { return properties; } public void setPropertyDefinitions(List<PropertyDefinition> properties) { this.properties = properties; } public List<PropertyObjectDefinition> getPropertyObjectDefinitions() { return propertyObjects; } public void setPropertyObjectDefinitions(List<PropertyObjectDefinition> propertyObjects) { this.propertyObjects = propertyObjects; } public List<PropertyObjectCollectionDefinition> getPropertyObjectCollectionDefinitions() { return propertyObjectCollections; } public void setPropertyObjectCollectionDefinitions( List<PropertyObjectCollectionDefinition> propertyObjectCollections) { this.propertyObjectCollections = propertyObjectCollections; } public JSONObject toJSON() { try { JSONObject jsonSection = new JSONObject(); jsonSection.put("name", getName()); jsonSection.put("short_name", getShortName()); jsonSection.put("local_name", TextUtil.format(getNamekey())); JSONArray jsonProperties = new JSONArray(); for (PropertyDefinition p : this.getPropertyDefinitions()) { jsonProperties.put(p.toJSON()); } jsonSection.put("properties", jsonProperties); JSONArray jsonPropertyObjects = new JSONArray(); for (PropertyObjectDefinition po : this.getPropertyObjectDefinitions()) { jsonPropertyObjects.put(po.toJSON()); } jsonSection.put("propertyObjects", jsonPropertyObjects); JSONArray jsonPropertyObjectCollections = new JSONArray(); for (PropertyObjectCollectionDefinition po : this.getPropertyObjectCollectionDefinitions()) { jsonPropertyObjectCollections.put(po.toJSON()); } jsonSection.put("propertyObjectCollections", jsonPropertyObjectCollections); return jsonSection; } catch (JSONException ex) { log.error("ERROR outputting JSON data", ex); return null; } } } /** Represents section of profile properties and objects. */ public static class DisplaySectionDefinition extends PropertyDefinitionHolder { private String sectionName = null; public DisplaySectionDefinition(String shortName, String namekey) { super("", shortName, namekey); this.sectionName = shortName; } public String getBasePath() { return getName(); } public String getName() { return sectionName; } } /** Represents a profile property object, such as an address, with multiple properties */ public static class PropertyObjectDefinition extends PropertyDefinitionHolder { public PropertyObjectDefinition(String path, String shortName, String namekey) { super(path, shortName, namekey); log.debug("Created propery object definition: " + getName()); } public String getBasePath() { return getName(); } public JSONObject toJSON() { try { JSONObject jsonPropertyObject = new JSONObject(); jsonPropertyObject.put("name", getName()); jsonPropertyObject.put("short_name", getShortName()); jsonPropertyObject.put("local_name", TextUtil.format(getNamekey())); JSONArray jsonProperties = new JSONArray(); for (PropertyDefinition p : this.getPropertyDefinitions()) { jsonProperties.put(p.toJSON()); } jsonPropertyObject.put("properties", jsonProperties); JSONArray jsonPropertyObjects = new JSONArray(); for (PropertyObjectDefinition po : this.getPropertyObjectDefinitions()) { jsonPropertyObjects.put(po.toJSON()); } jsonPropertyObject.put("propertyObjects", jsonPropertyObjects); JSONArray jsonPropertyObjectCollections = new JSONArray(); for (PropertyObjectCollectionDefinition po : this.getPropertyObjectCollectionDefinitions()) { jsonPropertyObjectCollections.put(po.toJSON()); } jsonPropertyObject.put("propertyObjectCollections", jsonPropertyObjectCollections); return jsonPropertyObject; } catch (JSONException ex) { log.error("ERROR outputting JSON data", ex); return null; } } } /** Represents a profile property object, such as an address, with multiple properties */ public static class PropertyObjectCollectionDefinition extends PropertyDefinitionHolder { public PropertyObjectCollectionDefinition(String path, String shortName, String namekey) { super(path, shortName + "_{n}", namekey); log.debug("Created propery collection definition: " + getName()); } public String getBasePath() { return getName(); } } /** Represents profile property definition */ public static class PropertyDefinition { private String path = null; private String shortName = null; private String namekey = null; private String type = null; private String defaultValue = null; private List<AllowedValue> allowedValues = new ArrayList<AllowedValue>(); public PropertyDefinition(String path, String shortName, String namekey, String type) { this.path = path; this.shortName = shortName; this.namekey = namekey; this.type = type; log.debug("Created propery definition: " + getName()); } public String getName() { return path + "_" + shortName; } public String getShortName() { return shortName; } public String getNamekey() { return namekey; } public String getType() { return type; } public String getDefaultValue() { return defaultValue; } public void setDefaultValue(String defaultValue) { this.defaultValue = defaultValue; } public List<AllowedValue> getAllowedValues() { return allowedValues; } public void setAllowedValues(List<AllowedValue> allowedValues) { this.allowedValues = allowedValues; } public JSONObject toJSON() { try { JSONObject jsonProperty = new JSONObject(); jsonProperty.put("name", getName()); jsonProperty.put("local_name", TextUtil.format(namekey)); jsonProperty.put("short_name", shortName); jsonProperty.put("type", type); if (defaultValue != null) { jsonProperty.put("defaultvalue", defaultValue); } if (allowedValues != null && allowedValues.size() > 0) { JSONArray jsonAllowedValues = new JSONArray(); for (AllowedValue allowedValue : allowedValues) { jsonAllowedValues.put(allowedValue.toJSON()); } jsonProperty.put("allowedValues", jsonAllowedValues); } return jsonProperty; } catch (JSONException ex) { log.error("ERROR outputting JSON data", ex); return null; } } } /** Represents profile property allowed value */ public static class AllowedValue { private String name = null; private String namekey = null; public AllowedValue(String name, String namekey) { this.name = name; this.namekey = namekey; } public String getName() { return name; } public String getNamekey() { return namekey; } public JSONObject toJSON() { try { JSONObject jsonAllowedObject = new JSONObject(); jsonAllowedObject.put("name", name); if (namekey != null) { jsonAllowedObject.put("namekey", namekey); jsonAllowedObject.put("local_name", TextUtil.format(namekey)); } return jsonAllowedObject; } catch (JSONException ex) { log.error("ERROR outputting JSON data", ex); return null; } } } protected void init(PropDefinition profileDef, InputStream input) throws SocialSiteException { try { XMLInputFactory factory = XMLInputFactory.newInstance(); XMLStreamReader parser = factory.createXMLStreamReader(input); String ns = null; // TODO: namespace for ProfileDef // hold the current things we're working on Map<String, DisplaySectionDefinition> sdefs = new LinkedHashMap<String, DisplaySectionDefinition>(); Stack<PropertyDefinitionHolder> propertyHolderStack = new Stack<PropertyDefinitionHolder>(); List<AllowedValue> allowedValues = null; PropertyDefinition pdef = null; for (int event = parser.next(); event != XMLStreamConstants.END_DOCUMENT; event = parser.next()) { switch (event) { case XMLStreamConstants.START_ELEMENT: log.debug("START ELEMENT -- " + parser.getLocalName()); if ("display-section".equals(parser.getLocalName())) { propertyHolderStack.push(new DisplaySectionDefinition(parser.getAttributeValue(ns, "name"), parser.getAttributeValue(ns, "namekey"))); } else if ("property".equals(parser.getLocalName())) { PropertyDefinitionHolder holder = propertyHolderStack.peek(); pdef = new PropertyDefinition(holder.getBasePath(), parser.getAttributeValue(ns, "name"), parser.getAttributeValue(ns, "namekey"), parser.getAttributeValue(ns, "type")); } else if ("object".equals(parser.getLocalName())) { PropertyDefinitionHolder holder = propertyHolderStack.peek(); propertyHolderStack.push(new PropertyObjectDefinition(holder.getBasePath(), parser.getAttributeValue(ns, "name"), parser.getAttributeValue(ns, "namekey"))); } else if ("collection".equals(parser.getLocalName())) { PropertyDefinitionHolder holder = propertyHolderStack.peek(); propertyHolderStack.push(new PropertyObjectCollectionDefinition(holder.getBasePath(), parser.getAttributeValue(ns, "name"), parser.getAttributeValue(ns, "namekey"))); } else if ("allowed-values".equals(parser.getLocalName())) { allowedValues = new ArrayList<AllowedValue>(); } else if ("value".equals(parser.getLocalName())) { AllowedValue allowedValue = new AllowedValue(parser.getAttributeValue(ns, "name"), parser.getAttributeValue(ns, "namekey")); allowedValues.add(allowedValue); } else if ("default-value".equals(parser.getLocalName())) { pdef.setDefaultValue(parser.getText()); } break; case XMLStreamConstants.END_ELEMENT: log.debug("END ELEMENT -- " + parser.getLocalName()); if ("display-section".equals(parser.getLocalName())) { DisplaySectionDefinition sdef = (DisplaySectionDefinition) propertyHolderStack.pop(); sdefs.put(sdef.getName(), sdef); } else if ("property".equals(parser.getLocalName())) { PropertyDefinitionHolder holder = propertyHolderStack.peek(); holder.getPropertyDefinitions().add(pdef); propertyDefs.put(pdef.getName(), pdef); pdef = null; } else if ("object".equals(parser.getLocalName())) { PropertyObjectDefinition odef = (PropertyObjectDefinition) propertyHolderStack.pop(); PropertyDefinitionHolder holder = propertyHolderStack.peek(); holder.getPropertyObjectDefinitions().add(odef); // add to list of all property object defs propertyObjectDefs.put(odef.getName(), odef); odef = null; } else if ("collection".equals(parser.getLocalName())) { PropertyObjectCollectionDefinition cdef = (PropertyObjectCollectionDefinition) propertyHolderStack .pop(); PropertyDefinitionHolder holder = propertyHolderStack.peek(); holder.getPropertyObjectCollectionDefinitions().add(cdef); // add to list of all property object defs propertyObjectCollectionDefs.put(cdef.getName(), cdef); cdef = null; } else if ("allowed-values".equals(parser.getLocalName())) { pdef.setAllowedValues(allowedValues); allowedValues = null; } break; case XMLStreamConstants.CHARACTERS: break; case XMLStreamConstants.CDATA: break; } // end switch } // end while parser.close(); profileDef.sectionDefs = sdefs; } catch (Exception ex) { throw new SocialSiteException("ERROR parsing profile definitions", ex); } } public JSONObject toJSON() { try { JSONObject jsonProfile = new JSONObject(); JSONArray jsonSections = new JSONArray(); for (String key : this.sectionDefs.keySet()) { DisplaySectionDefinition section = this.sectionDefs.get(key); jsonSections.put(section.toJSON()); } jsonProfile.put("sections", jsonSections); return jsonProfile; } catch (JSONException ex) { log.error("ERROR outputting JSON data", ex); return null; } } }