Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/
package com.codename1.properties;
import com.codename1.io.Externalizable;
import com.codename1.io.JSONParser;
import com.codename1.io.Log;
import com.codename1.io.Storage;
import com.codename1.io.Util;
import com.codename1.processing.Result;
import com.codename1.ui.CN;
import com.codename1.ui.EncodedImage;
import com.codename1.ui.Image;
import com.codename1.util.Base64;
import com.codename1.util.regex.StringReader;
import com.codename1.xml.Element;
import com.codename1.xml.XMLWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Maps the properties that are in a class/object and provides access to them so tools such as ORM
* can implicitly access them for us. This class also holds the class level meta-data for a specific property
* or class. It also provides utility level tools e.g. toString implementation etc.
*
* @author Shai Almog
*/
public class PropertyIndex implements Iterable {
private final PropertyBase[] properties;
private static Map> metadata = new LinkedHashMap>();
PropertyBusinessObject parent;
private final String name;
/**
* The constructor is essential for a proper property business object
*
* @param parent the parent object instance
* @param name the name of the parent class
* @param properties the list of properties in the object
*/
public PropertyIndex(PropertyBusinessObject parent, String name, PropertyBase... properties) {
this.properties = properties;
this.parent = parent;
this.name = name;
for(PropertyBase p : properties) {
p.parent = this;
}
}
/**
* The name of the parent business object
* @return a unique name for the parent
*/
public String getName() {
return name;
}
/**
* Returns a property by its name
* @param name the name of the property (case sensitive)
* @return the property or null
*/
public PropertyBase get(String name) {
for(PropertyBase p : properties) {
if(p.getName().equals(name)) {
return p;
}
}
return null;
}
/**
* Returns a property by its name regardless of case sensitivity for the name
* @param name the name of the property (case insensitive)
* @return the property or null
*/
public PropertyBase getIgnoreCase(String name) {
for(PropertyBase p : properties) {
if(p.getName().equalsIgnoreCase(name)) {
return p;
}
}
return null;
}
/**
* Allows us to get an individual property within the object instance
* @param i the index of the property
* @return the property instance
*/
public PropertyBase get(int i) {
return properties[i];
}
/**
* The number of properties in the class
* @return number of properties in the class
*/
public int getSize() {
return properties.length;
}
/**
* Allows us to traverse the properties with a for-each statement
* @return an iterator instance
*/
public Iterator iterator() {
return new Iterator() {
int off = 0;
public boolean hasNext() {
return off < properties.length;
}
public void remove() {
}
public PropertyBase next() {
int i = off;
off++;
return properties[i];
}
};
}
private HashMap getProps() {
HashMap m = metadata.get(parent.getClass().getName());
if(m == null) {
m = new HashMap();
metadata.put(parent.getClass().getName(), m);
}
return m;
}
/**
* Allows us to fetch class meta data not to be confused with standard properties
* @param meta the meta data unique name
* @return the object instance
*/
public Object getMetaDataOfClass(String meta) {
return getProps().get(meta);
}
/**
* Sets class specific metadata
*
* @param meta the name of the meta data
* @param o object value for the meta data
*/
public void putMetaDataOfClass(String meta, Object o) {
if(o == null) {
getProps().remove(meta);
} else {
getProps().put(meta, o);
}
}
/**
* Returns a user readable printout of the property values which is useful for debugging
* @return user readable printout of the property values which is useful for debugging
*/
public String toString() {
return toString(true);
}
/**
* Returns a user readable printout of the property values which is useful for debugging
*
* @param includeNewline true to indicate that newline characters should be included
* @return user readable printout of the property values which is useful for debugging
*/
public String toString(boolean includeNewline) {
StringBuilder b = new StringBuilder(name);
b.append(" : {");
if(includeNewline) {
b.append('\n');
}
for(PropertyBase p : this) {
b.append(p.getName());
b.append(" = ");
b.append(p.toString());
if(includeNewline) {
b.append('\n');
}
}
b.append("}");
return b.toString();
}
/**
* This is useful for JSON parsing, it allows converting JSON map data to objects
* @param m the map
*/
public void populateFromMap(Map m) {
populateFromMap(m, null);
}
private Object listParse(List l, Class extends PropertyBusinessObject>recursiveType) throws InstantiationException, IllegalAccessException {
ArrayList al = new ArrayList();
for(Object o : l) {
if(o instanceof Map) {
PropertyBusinessObject po = (PropertyBusinessObject)recursiveType.newInstance();
po.getPropertyIndex().populateFromMap((Map)o, recursiveType);
al.add(po);
continue;
}
if(o instanceof List) {
al.add(listParse((List)o,recursiveType));
continue;
}
al.add(o);
}
return al;
}
/**
* Sets one of the builtin simple objects into a property
* @param p the property base
* @param val the object value
* @return true if successful
*/
public boolean setSimpleObject(PropertyBase p, Object val) {
if(val == null) {
p.setImpl(null);
return true;
}
if(p.getGenericType() == null || p.getGenericType() == String.class) {
p.setImpl(val.toString());
return true;
}
if(p instanceof IntProperty) {
p.setImpl(Util.toIntValue(val));
return true;
}
if(p instanceof BooleanProperty) {
p.setImpl(Util.toBooleanValue(val));
return true;
}
if(p instanceof LongProperty) {
p.setImpl(Util.toLongValue(val));
return true;
}
if(p instanceof FloatProperty) {
p.setImpl(Util.toFloatValue(val));
return true;
}
if(p instanceof DoubleProperty) {
p.setImpl(Util.toDoubleValue(val));
return true;
}
if(p.getGenericType() == Image.class || p.getGenericType() == EncodedImage.class) {
if(val instanceof Image) {
p.setImpl(val);
} else {
if(val instanceof byte[]) {
p.setImpl(EncodedImage.create((byte[])val));
} else {
p.setImpl(EncodedImage.create(Base64.decode(((String)val).getBytes())));
}
}
return true;
}
if(p.getGenericType() == Date.class) {
p.setImpl(Util.toDateValue(val));
return true;
}
return false;
}
/**
* This is useful for JSON parsing, it allows converting JSON map data to objects
* @param m the map
* @param recursiveType when running into map types we create this object type
*/
public void populateFromMap(Map m, Class extends PropertyBusinessObject>recursiveType) {
try {
for(PropertyBase p : this) {
MapAdapter ma = MapAdapter.checkInstance(p);
if(ma != null) {
ma.setFromMap(p, m);
continue;
}
Object val = m.get(p.getName());
if(val != null) {
if(val instanceof List) {
if(p instanceof CollectionProperty) {
if(recursiveType != null) {
if(((CollectionProperty)p) != null) {
((CollectionProperty)p).clear();
}
for(Object e : (Collection)val) {
if(e instanceof Map) {
Class eType = ((CollectionProperty) p).getGenericType();
// maybe don't use recursiveType here anymore???
// elementType is usually sufficient...
Class type = (eType == null)? recursiveType : eType;
PropertyBusinessObject po = (PropertyBusinessObject)type.newInstance();
po.getPropertyIndex().populateFromMap((Map)e, type);
((CollectionProperty)p).add(po);
continue;
}
if(e instanceof List) {
((CollectionProperty)p).add(listParse((List)e, recursiveType));
continue;
}
((CollectionProperty)p).add(e);
}
} else {
List l = (List)val;
if(!l.isEmpty()) {
if(l.get(0) instanceof PropertyBusinessObject
|| l.get(0) instanceof String
|| l.get(0) instanceof Character
|| l.get(0) instanceof Boolean
|| l.get(0) instanceof Integer
|| l.get(0) instanceof Long
|| l.get(0) instanceof Float
|| l.get(0) instanceof Double
|| l.get(0) instanceof Byte
|| l.get(0) instanceof Short
|| p.getGenericType() == null) {
((CollectionProperty)p).set((Collection)val);
} else {
Class eType = p.getGenericType();
for(Object e : l) {
PropertyBusinessObject po = (PropertyBusinessObject)eType.newInstance();
po.getPropertyIndex().populateFromMap((Map)e, eType);
((CollectionProperty)p).add(po);
}
}
} else {
((CollectionProperty)p).set((Collection)val);
}
}
}
continue;
}
if(val instanceof Map) {
if(p instanceof MapProperty) {
((MapProperty)p).clear();
for(Object k : ((Map)val).keySet()) {
Object value = ((Map)val).get(k);
Class keyType = ((MapProperty)p).getKeyType();
if(keyType != null &&
PropertyBusinessObject.class.isAssignableFrom(keyType)) {
PropertyBusinessObject po = (PropertyBusinessObject)keyType.newInstance();
po.getPropertyIndex().populateFromMap((Map)val, keyType);
k = po;
}
Class valueType = ((MapProperty)p).getValueType();
if(valueType != null &&
PropertyBusinessObject.class.isAssignableFrom(valueType)) {
Map contentMap = (Map)val;
for(String kk : contentMap.keySet()) {
PropertyBusinessObject po = (PropertyBusinessObject)valueType.newInstance();
Map vv = (Map)contentMap.get(kk);
po.getPropertyIndex().populateFromMap(vv, valueType);
((MapProperty)p).set(kk, po);
}
continue;
} else {
if(value instanceof Map) {
PropertyBusinessObject po = (PropertyBusinessObject)p.get();
po.getPropertyIndex().populateFromMap((Map)value, recursiveType);
((MapProperty)p).set(k, po);
continue;
}
if(value instanceof List) {
((MapProperty)p).set(k, listParse((List)value, recursiveType));
continue;
}
}
((MapProperty)p).set(k, value);
}
continue;
} else {
if(p.get() instanceof PropertyBusinessObject) {
PropertyBusinessObject po = (PropertyBusinessObject)p.get();
po.getPropertyIndex().populateFromMap((Map)val, recursiveType);
} else {
if(p.getGenericType() != null) {
Object o = p.getGenericType().newInstance();
if(o instanceof PropertyBusinessObject) {
((PropertyBusinessObject)o).getPropertyIndex().populateFromMap((Map)val);
p.setImpl(o);
}
} else {
if(recursiveType != null) {
PropertyBusinessObject po = (PropertyBusinessObject)recursiveType.newInstance();
po.getPropertyIndex().populateFromMap((Map)val, recursiveType);
p.setImpl(po);
}
}
}
}
continue;
}
if(setSimpleObject(p, val)) {
continue;
}
p.setImpl(val);
}
}
} catch(InstantiationException err) {
Log.e(err);
throw new RuntimeException("Can't create instanceof class: " + err);
} catch(IllegalAccessException err) {
Log.e(err);
throw new RuntimeException("Can't create instanceof class: " + err);
}
}
/**
* This is useful in converting a property object to JSON
* @return a map representation of the properties
*/
public Map toMapRepresentation() {
return toMapRepresentationImpl("mapExclude");
}
/**
* This is useful in converting a property object to JSON
* @return a map representation of the properties
*/
private Map toMapRepresentationImpl(String excludeFlag) {
Map m = new LinkedHashMap();
for(PropertyBase p : this) {
if(p.getClientProperty(excludeFlag) != null) {
continue;
}
MapAdapter ma = MapAdapter.checkInstance(p);
if(ma != null) {
ma.placeInMap(p, m);
continue;
}
if(p instanceof MapProperty) {
MapProperty pp = (MapProperty)p;
m.put(p.getName(), pp.asExplodedMap());
continue;
}
if(p instanceof CollectionProperty) {
CollectionProperty pp = (CollectionProperty)p;
m.put(p.getName(), pp.asExplodedList());
continue;
}
if(p instanceof Property) {
Property pp = (Property)p;
if(pp.get() != null) {
if(pp.getGenericType() != null && PropertyBusinessObject.class.isAssignableFrom(pp.getGenericType())) {
m.put(p.getName(), ((PropertyBusinessObject)pp.get()).getPropertyIndex().toMapRepresentationImpl(excludeFlag));
} else {
m.put(p.getName(), pp.get());
}
}
}
}
return m;
}
/**
* Converts the object to a JSON representation
* @return a JSON String
*/
public String toJSON() {
return Result.fromContent(toMapRepresentationImpl("jsonExclude")).toString();
}
/**
* Returns an element object mapping to the current object hierarchy similar
* to the map object
* @return an XML parser element
*/
public Element asElement() {
return new PropertyXMLElement(this);
}
/**
* Converts the object to an XML representation
* @return an XML String
*/
public String toXML() {
XMLWriter w = new XMLWriter(true);
return w.toXML(asElement());
}
/**
* Toggles whether a given property should act as a text element for this
* object
* @param p the property that should act as a text element
* @param t true to activate the text element false to remove it
*/
public void setXmlTextElement(PropertyBase p, boolean t) {
if(t) {
p.putClientProperty("xmlTextElement", Boolean.TRUE);
} else {
p.putClientProperty("xmlTextElement", null);
}
}
/**
* Toggles whether a given property should act as a text element for this
* object
* @param p the property
* @return true if this is a text element
*/
public boolean isXmlTextElement(PropertyBase p) {
Boolean b = (Boolean)p.getClientProperty("xmlTextElement");
return b != null && b.booleanValue();
}
/**
* Returns the property that contains the XML text e.g. {@code property value}
* @return the property representing text XML or null if no such property was set
*/
public PropertyBase getXmlTextElement() {
for(PropertyBase b : this) {
if(isXmlTextElement(b)) {
return b;
}
}
return null;
}
/**
* Converts the XML element to this object hierarchy
* @param e the element
*/
public void fromXml(Element e) {
Hashtable atts = e.getAttributes();
if(atts != null) {
for(Object a : atts.keySet()) {
PropertyBase pb = get((String)a);
if(pb != null) {
setSimpleObject(pb, atts.get(a));
}
}
}
int cc = e.getNumChildren();
for(int iter = 0 ; iter < cc ; iter++) {
Element chld = e.getChildAt(iter);
if(chld.isTextElement()) {
PropertyBase pt = getXmlTextElement();
if(pt != null) {
String t = chld.getText();
pt.setImpl(t);
}
continue;
}
PropertyBase pb = get(chld.getTagName());
Class cls = pb.getGenericType();
if(cls.isAssignableFrom(PropertyBusinessObject.class)) {
try {
PropertyBusinessObject business = (PropertyBusinessObject)cls.newInstance();
business.getPropertyIndex().fromXml(chld);
if(pb instanceof ListProperty) {
((ListProperty)pb).add(business);
} else {
pb.setImpl(business);
}
} catch(InstantiationException ex) {
Log.e(ex);
} catch(IllegalAccessException ex) {
Log.e(ex);
}
}
}
}
/**
* This method works similarly to a constructor, it accepts the values for the properties in the order
* they appear within the index
* @param values values of properties in the order they appear in the index
*/
public void init(Object... values) {
int offset = 0;
for(PropertyBase pb : properties) {
if(pb instanceof CollectionProperty) {
if(values[offset] instanceof Object[]) {
((CollectionProperty) pb).addAll(Arrays.asList((Object[])values[offset]));
} else {
((CollectionProperty) pb).addAll((Collection) values[offset]);
}
} else {
pb.setImpl(values[offset]);
}
offset++;
}
}
/**
* Writes the JSON string to storage, it's a shortcut for writing/generating the JSON
* @param name the name of the storage file
*/
public void storeJSON(String name) {
try {
OutputStream os = Storage.getInstance().createOutputStream(name);
os.write(toJSON().getBytes("UTF-8"));
os.close();
} catch(IOException err) {
Log.e(err);
throw new RuntimeException(err.toString());
}
}
/**
* Writes the JSON string to storage, it's a shortcut for writing/generating the JSON
* @param name the name of the storage file
* @param objs a list of business objects
*/
public static void storeJSONList(String name, List extends PropertyBusinessObject> objs) {
try {
OutputStream os = Storage.getInstance().createOutputStream(name);
os.write(toJSONList(objs).getBytes());
os.close();
} catch(IOException err) {
Log.e(err);
throw new RuntimeException(err.toString());
}
}
/**
* Creates a JSON string, containing the list of property business objects
*
* @param objs a list of business objects
* @return the JSON string
*/
public static String toJSONList(List extends PropertyBusinessObject> objs) {
StringBuilder b = new StringBuilder("[");
boolean first = true;
for (PropertyBusinessObject pb : objs) {
if (first) {
first = false;
} else {
b.append(",\n");
}
b.append(pb.getPropertyIndex().toJSON());
}
b.append("]");
return b.toString();
}
/**
* Loads JSON containing a list of property objects of this type
* @param name the name of the storage
* @return list of property objects matching this type
*/
public List loadJSONList(String name) {
try {
if(Storage.getInstance().exists(name)) {
return loadJSONList(Storage.getInstance().createInputStream(name));
}
InputStream is = CN.getResourceAsStream("/" + name);
return loadJSONList(is);
} catch(IOException err) {
Log.e(err);
throw new RuntimeException(err.toString());
}
}
/**
* Loads JSON containing a list of property objects of this type
* @param stream the input stream
* @return list of property objects matching this type
*/
public List loadJSONList(InputStream stream)
throws IOException {
JSONParser jp = new JSONParser();
jp.setUseBooleanInstance(true);
jp.setUseLongsInstance(true);
List response = new ArrayList();
Map result = jp.parseJSON(new InputStreamReader(stream, "UTF-8"));
List