Added exception handling in the main loop for the web server to avoid the main loop thread getting killed off due to an unexpected/unhandled exception.

Moved code for JSON handling and metadata/metadata container into the Common project from the Foundation project.
This commit is contained in:
wcrisman
2014-09-16 14:01:31 -07:00
parent 1a8fd62dd8
commit b48e81bfe0
39 changed files with 930 additions and 994 deletions

View File

@@ -5,7 +5,7 @@
* verson 1 which accompanies this distribution, and is available at * verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt * http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/ */
package com.foundation.common; package com.common.metadata;
import java.io.Externalizable; import java.io.Externalizable;
import com.common.io.IExternalizable; import com.common.io.IExternalizable;

View File

@@ -5,7 +5,7 @@
* verson 1 which accompanies this distribution, and is available at * verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt * http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/ */
package com.foundation.common; package com.common.metadata;
import java.io.Externalizable; import java.io.Externalizable;
import java.io.IOException; import java.io.IOException;

View File

@@ -0,0 +1,18 @@
package com.common.util.json;
import java.io.StringWriter;
import com.common.metadata.MetadataContainer;
import com.common.util.LiteHashSet;
/**
* Classes implement this if they know how to stream to/from JSON formatted text.
*/
public interface IJsonAware {
/**
* Converts the entity into a JSON string.
* Includes all attributes that are not cyclical.
* @param context The context for the JSON streaming operation.
*/
public void toJson(IJsonContext context);
}//IJsonAware//

View File

@@ -0,0 +1,35 @@
package com.common.util.json;
import java.io.IOException;
import java.io.StringWriter;
import com.common.metadata.MetadataContainer;
import com.common.util.LiteHashSet;
public interface IJsonContext {
/**
* @return The container containing metadata on what to include in the JSON.
*/
public MetadataContainer getMetadataContainer();
/**
* @return Writes a new line character to the writer and indents as required. New line and indent characters are optional and may be ignored (not outputted) based on the user's preferences when the context was setup.
*/
public void writeNewLine();
/**
* @return The set of included objects, used to prevent recursion.
*/
public LiteHashSet getIncluded();
/**
* @return The writer used to write the output.
*/
public StringWriter getWriter();
/**
* @return Whether the output should be compacted as much as possible.
*/
public boolean isCompact();
/**
* Writes the given object to the JSON output.
* @param value The value to write.
*/
public void toJson(Object value) throws IOException;
}//IJsonContext//

View File

@@ -1,4 +1,4 @@
package com.foundation.util.json; package com.common.util.json;
/* /*
Copyright (c) 2002 JSON.org Copyright (c) 2002 JSON.org

View File

@@ -1,4 +1,4 @@
package com.foundation.util.json; package com.common.util.json;
/** /**
* The JSONException is thrown by the JSON.org classes when things are amiss. * The JSONException is thrown by the JSON.org classes when things are amiss.

View File

@@ -1,4 +1,4 @@
package com.foundation.util.json; package com.common.util.json;
/* /*
Copyright (c) 2002 JSON.org Copyright (c) 2002 JSON.org

View File

@@ -1,4 +1,4 @@
package com.foundation.util.json; package com.common.util.json;
/** /**
* The <code>JSONString</code> interface allows a <code>toJSONString()</code> * The <code>JSONString</code> interface allows a <code>toJSONString()</code>

View File

@@ -1,4 +1,4 @@
package com.foundation.util.json; package com.common.util.json;
/* /*
Copyright (c) 2006 JSON.org Copyright (c) 2006 JSON.org

View File

@@ -1,4 +1,4 @@
package com.foundation.util.json; package com.common.util.json;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;

View File

@@ -1,4 +1,4 @@
package com.foundation.util.json; package com.common.util.json;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;

View File

@@ -0,0 +1,642 @@
package com.common.util.json;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.common.comparison.Comparator;
import com.common.debug.Debug;
import com.common.exception.InvalidArgumentException;
import com.common.util.ICollection;
import com.common.util.IHashMap;
import com.common.util.IIterator;
import com.common.util.LiteHashMap;
import com.common.util.LiteHashSet;
import com.common.util.LiteList;
import com.common.util.Map.Iterator;
import com.common.metadata.*;
/**
* Reads and writes JSON formatted data.
* Uses hashmaps and lists for the java side data structure.
*/
public class JsonBuilder {
/**
* The context class used to build JSON output for a graph of objects.
*/
private static class JsonContext implements IJsonContext {
private String indent = null;
private int indentCount = 0;
private StringWriter writer = null;
private LiteHashSet included = null;
private MetadataContainer metadataContainer = null;
public JsonContext(String indent, MetadataContainer metadataContainer, StringWriter writer) {
this.indent = indent == null ? "" : indent;
this.metadataContainer = metadataContainer;
this.writer = writer;
}//JsonContext()//
public MetadataContainer getMetadataContainer() {
return metadataContainer;
}//getMetadataContainer()//
public void writeNewLine() {
if(indent != null) {
writer.write('\n');
for(int indentCounter = 0; indentCounter < indentCount; indentCounter++) {
writer.write(indent);
}//for//
}//if//
else {
writer.write(' ');
}//else//
}//writeNewLine()//
public LiteHashSet getIncluded() {
return included;
}//getIncluded()//
public StringWriter getWriter() {
return writer;
}//getWriter()//
public boolean isCompact() {
return indent == null;
}//isCompact()//
public void toJson(Object value) throws IOException {
indentCount++;
//Write the value.//
if(value == null || value.equals(null)) {
writer.write("null");
}//if//
else if(value instanceof IJsonAware) {
((IJsonAware) value).toJson(this);
}//else if//
else if(value instanceof ICollection) {
toJson((ICollection) value);
}//else if//
else if(value instanceof IHashMap) {
toJson((IHashMap) value);
}//else if//
else if(value instanceof java.util.Map) {
toJson((java.util.Map) value);
}//else if//
else if(value instanceof java.util.Collection) {
toJson((java.util.Collection) value);
}//else if//
else if(value.getClass().isArray()) {
toJson((Array) value);
}//else if//
else if(value instanceof Number) {
if(value instanceof Double && (((Double) value).isInfinite() || ((Double) value).isNaN()) || value instanceof Float && (((Float) value).isInfinite() || ((Float) value).isNaN())) {
//TODO: Can we convert the number perhaps? Show a max value or something?
throw new RuntimeException("JSON does not allow non-finite numbers.");
}//if//
String s = value.toString().toLowerCase();
//Remove trailing zeros and the decimal if possible.//
if(s.indexOf('.') > 0 && s.indexOf('e') < 0) {
int sIndex = s.length() - 1;
while(s.charAt(sIndex) == '0') {
sIndex--;
}//while//
if(s.charAt(sIndex) == '.') {
s = s.substring(0, sIndex);
}//if//
else {
s = s.substring(0, sIndex + 1);
}//else//
}//if//
writer.write(s);
}//else if//
else if(value instanceof Boolean) {
writer.write(value.toString());
}//else if//
else if(value instanceof String) {
jsonQuote((String) value, writer);
}//else if//
else {
jsonQuote(value.toString(), writer);
}//else if//
indentCount--;
}//toJson()//
/**
* Writes an array of values to the JSON stream. This method is intended for internal framework use and is subject to change.
* @param value The collection.
*/
private void toJson(IHashMap value) throws IOException {
writer.write("{");
if(value != null) {
boolean isFirst = true;
for(IIterator iterator = value.keyIterator(); iterator.hasNext(); ) {
Object key = iterator.next();
Object next = value.get(key);
if(!isFirst) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
else {
isFirst = false;
}//else//
if(key != null && !(key instanceof String)) {
key = key.toString();
}//if//
//Just roll over null's by converting them to strings. Better than an error IMO.
if(key == null) {
key = "null";
}//if//
toJson(key);
writer.write(':');
if(indent != null) {
writer.write(' ');
}//if//
toJson(next);
}//for//
}//if//
writer.write("}");
}//toJson()//
/**
* Writes an array of values to the JSON stream. This method is intended for internal framework use and is subject to change.
* @param value The collection.
*/
private void toJson(ICollection value) throws IOException {
writer.write("[");
if(value != null) {
boolean isFirst = true;
for(IIterator iterator = value.iterator(); iterator.hasNext(); ) {
Object next = iterator.next();
if(!isFirst) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
else {
isFirst = false;
}//else//
toJson(next);
}//for//
}//if//
writer.write("]");
}//toJson()//
/**
* Writes an array of values to the JSON stream. This method is intended for internal framework use and is subject to change.
* @param value The collection.
*/
private void toJson(java.util.Map value) throws IOException {
writer.write("{");
if(value != null) {
boolean isFirst = true;
for(java.util.Iterator iterator = value.keySet().iterator(); iterator.hasNext(); ) {
Object key = iterator.next();
Object next = value.get(key);
if(!isFirst) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
else {
isFirst = false;
}//else//
if(key != null && !(key instanceof String)) {
key = key.toString();
}//if//
//Just roll over null's by converting them to strings. Better than an error IMO.
if(key == null) {
key = "null";
}//if//
toJson(key);
writer.write(':');
if(indent != null) {
writer.write(' ');
}//if//
toJson(next);
}//for//
}//if//
writer.write("}");
}//toJson()//
/**
* Writes an array of values to the JSON stream. This method is intended for internal framework use and is subject to change.
* @param value The collection.
*/
private void toJson(java.util.Collection value) throws IOException {
writer.write("[");
if(value != null) {
boolean isFirst = true;
for(java.util.Iterator iterator = value.iterator(); iterator.hasNext(); ) {
Object next = iterator.next();
if(!isFirst) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
else {
isFirst = false;
}//else//
toJson(next);
}//for//
}//if//
writer.write("]");
}//toJson()//
/**
* Writes an array of values to the JSON stream. This method is intended for internal framework use and is subject to change.
* @param value The array.
*/
private void toJson(Array value) throws IOException {
writer.write("[");
if(value != null) {
int length = Array.getLength(value);
Class valueType = value.getClass().getComponentType();
if(valueType.isPrimitive()) {
switch(valueType.getName().charAt(0)) {
case 'Z':
for(int index = 0; index < length; index++) {
if(index > 0) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
writer.write(Array.getBoolean(value, index) ? "true" : "false");
}//for//
break;
case 'C':
for(int index = 0; index < length; index++) {
if(index > 0) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
//TODO: This could be optimized.
jsonQuote("" + Array.getChar(value, index), writer);
}//for//
break;
case 'B':
for(int index = 0; index < length; index++) {
if(index > 0) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
writer.write(Byte.toString(Array.getByte(value, index)));
}//for//
break;
case 'S':
for(int index = 0; index < length; index++) {
if(index > 0) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
writer.write(Short.toString(Array.getShort(value, index)));
}//for//
break;
case 'I':
for(int index = 0; index < length; index++) {
if(index > 0) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
writer.write(Integer.toString(Array.getInt(value, index)));
}//for//
break;
case 'J':
for(int index = 0; index < length; index++) {
if(index > 0) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
writer.write(Long.toString(Array.getLong(value, index)));
}//for//
break;
case 'F':
for(int index = 0; index < length; index++) {
if(index > 0) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
writer.write(Float.toString(Array.getFloat(value, index)));
}//for//
break;
case 'D':
for(int index = 0; index < length; index++) {
if(index > 0) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
writer.write(Double.toString(Array.getDouble(value, index)));
}//for//
break;
}//switch//
}//if//
else {
for(int index = 0; index < length; index++) {
Object next = Array.get(value, index);
toJson(next);
}//for//
}//else//
}//if//
writer.write("]");
}//toJson()//
public void jsonQuote(String string, Writer writer) throws IOException {
if(string == null || string.length() == 0) {
writer.write("\"\"");
}//if//
else {
char previousChar;
char currentChar = 0;
String hex;
int len = string.length();
writer.write('"');
for(int index = 0; index < len; index += 1) {
previousChar = currentChar;
currentChar = string.charAt(index);
switch(currentChar) {
case '\\':
case '"': {
writer.write('\\');
writer.write(currentChar);
break;
}//case//
case '/': {
if(previousChar == '<') {
writer.write('\\');
}//if//
writer.write(currentChar);
break;
}//case//
case '\b':
writer.write("\\b");
break;
case '\t':
writer.write("\\t");
break;
case '\n':
writer.write("\\n");
break;
case '\f':
writer.write("\\f");
break;
case '\r':
writer.write("\\r");
break;
default: {
if((currentChar < ' ') ||
(currentChar >= '\u0080' && currentChar < '\u00a0') ||
(currentChar >= '\u2000' && currentChar < '\u2100')) {
hex = "000" + Integer.toHexString(currentChar);
writer.write("\\u" + hex.substring(hex.length() - 4));
}//if//
else {
writer.write(currentChar);
}//else//
}//default//
}//switch//
}//for//
writer.write('"');
}//else//
}//jsonQuote()//
}//JsonContext//
private JsonBuilder() {
}//JsonBuilder()//
private static LiteHashMap readObject(JSONObject object) throws JSONException {
String[] keys = JSONObject.getNames(object);
LiteHashMap result = new LiteHashMap(keys.length > 10 ? keys.length : 10);
for(int index = 0; index < keys.length; index++) {
Object value = object.get(keys[index]);
if(value instanceof JSONObject) {
value = readObject((JSONObject) value);
}//if//
else if(value instanceof JSONArray) {
value = readArray((JSONArray) value);
}//else if//
else if(value == JSONObject.NULL) {
value = null;
}//else if//
result.put(keys[index], value);
}//for//
return result;
}//readObject()//
private static LiteList readArray(JSONArray array) throws JSONException {
LiteList result = new LiteList(array.length() > 10 ? array.length() : 10);
for(int index = 0; index < array.length(); index++) {
Object value = array.get(index);
if(value instanceof JSONObject) {
value = readObject((JSONObject) value);
}//if//
else if(value instanceof JSONArray) {
value = readArray((JSONArray) value);
}//else if//
else if(value == JSONObject.NULL) {
value = null;
}//else if//
result.add(value);
}//for//
return result;
}//readArray()//
/**
* Converts the JSON string into a collection of LiteHashMap and LiteList instances.
* Note that we currently cannot inflate the original objects containing the data (such as Entity and specialized Collections).
* @param json The JSON string.
* @return The map for the JSON object.
*/
public static LiteHashMap readJson(String json) {
try {
JSONTokener tokener = new JSONTokener(json);
//TODO: It may be an array starting the JSON, not an object.
JSONObject object = new JSONObject(tokener);
return readObject(object);
}//try//
catch(JSONException e) {
Debug.log(e);
throw new InvalidArgumentException("Invalid JSON string.");
}//catch//
}//readJson()//
private static JSONObject writeObject(LiteHashMap object) throws JSONException {
JSONObject result = new JSONObject();
for(IIterator iterator = object.keyIterator(); iterator.hasNext(); ) {
String key = (String) iterator.next();
Object value = object.get(key);
if(value instanceof LiteHashMap) {
value = writeObject((LiteHashMap) value);
}//if//
else if(value instanceof LiteList) {
value = writeArray((LiteList) value);
}//else if//
else if(value == null) {
value = JSONObject.NULL;
}//else if//
result.put(key, value);
}//for//
return result;
}//writeObject()//
private static JSONArray writeArray(LiteList array) throws JSONException {
JSONArray result = new JSONArray();
for(int index = 0; index < array.getSize(); index++) {
Object value = array.get(index);
if(value instanceof LiteHashMap) {
value = writeObject((LiteHashMap) value);
}//if//
else if(value instanceof LiteList) {
value = writeArray((LiteList) value);
}//else if//
else if(value == null) {
value = JSONObject.NULL;
}//else if//
result.put(value);
}//for//
return result;
}//writeArray()//
/**
* Converts the value into a compact JSON string.
* Includes all attributes that are not cyclical.
* @param value The value to be converted (it will delve into collections and examine Entity objects to build the JSON string).
* @return The JSON formatted string for the tree of objects.
*/
public static String writeJson(Object value) {
return writeJson(value, null, null);
}//writeJson()//
/**
* Converts the value into a JSON string.
* Includes all attributes that are not cyclical.
* @param indent The indent string to be used, or null if spacing should be minimized.
* @return The JSON formatted string for the tree of objects.
*/
public static String writeJson(Object value, String indent) {
return writeJson(value, null, indent);
}//toJson()//
/**
* Converts the value into a compact JSON string.
* Includes all attributes that are not cyclical.
* @param metadataContainer The container containing metadata on what to include in the JSON.
* @return The JSON formatted string for the tree of objects.
*/
public static String writeJson(Object value, MetadataContainer metadataContainer) {
return writeJson(value, metadataContainer, null);
}//toJson()//
/**
* Converts the value into a JSON string.
* Includes all attributes that are not cyclical.
* @param metadataContainer The container containing metadata on what to include in the JSON.
* @param indent The indent string to be used, or null if spacing should be minimized.
* @return The JSON formatted string for the tree of objects.
*/
public static String writeJson(Object value, MetadataContainer metadataContainer, String indent) {
String result = null;
if(value != null) {
try {
JsonContext context = new JsonContext(indent, metadataContainer, new StringWriter(10000));
context.toJson(value);
result = context.getWriter().toString();
}//try//
catch(IOException e) {
//Shouldn't ever occur.//
Debug.log(e);
}//catch//
catch(Throwable e) {
Debug.log(e);
}//catch//
}//if//
return result;
}//writeJson()//
}//JsonBuilder//

View File

@@ -31,12 +31,17 @@ public ResourceRequestHandler() {
try { try {
InputStream in = getClass().getClassLoader().getResourceAsStream("framework.js"); InputStream in = getClass().getClassLoader().getResourceAsStream("framework.js");
try { if(in != null) {
frameworkJavascript = StreamSupport.readText(in, "UTF8"); try {
}//try// frameworkJavascript = StreamSupport.readText(in, "UTF8");
finally { }//try//
try {in.close();} catch(Throwable e) {} finally {
}//finally// try {in.close();} catch(Throwable e) {}
}//finally//
}//if//
else {
Debug.log("Warning: framework.js not found!");
}//else//
}//try// }//try//
catch(Throwable e) { catch(Throwable e) {
Debug.log("Failed to read the framework.js file from the framework jar.", e); Debug.log("Failed to read the framework.js file from the framework jar.", e);

View File

@@ -486,12 +486,15 @@ public WebApplication(String name, WebOptions options, Application application)
}//if// }//if//
}//while// }//while//
SessionStore query = new SessionStore(WebApplication.this.application); //If a transaction service is setup (it usually is) then remove the session store from the repository.//
DeleteTransactionDefinition definition = new DeleteTransactionDefinition(query, null); if(WebApplication.this.application.getTransactionService() != null) {
definition.addRequirement(query, query.UPDATE_TIMESTAMP, Operator.LESS_THAN, new Date(currentTime - sessionRepositoryTimeout)); SessionStore query = new SessionStore(WebApplication.this.application);
DeleteTransaction transaction = new DeleteTransaction(definition, query); DeleteTransactionDefinition definition = new DeleteTransactionDefinition(query, null);
transaction.setDebugLevel(Transaction.DEBUG_ERRORS); definition.addRequirement(query, query.UPDATE_TIMESTAMP, Operator.LESS_THAN, new Date(currentTime - sessionRepositoryTimeout));
query.getTransactionService().delete(transaction); DeleteTransaction transaction = new DeleteTransaction(definition, query);
transaction.setDebugLevel(Transaction.DEBUG_ERRORS);
query.getTransactionService().delete(transaction);
}//if//
}//try// }//try//
catch(Throwable e) { catch(Throwable e) {
Debug.log(e); Debug.log(e);

View File

@@ -1851,170 +1851,180 @@ public class WebServer {
Debug.log(e); Debug.log(e);
}//catch// }//catch//
if(key != null) { try {
final boolean isWrite = key.isWritable(); if(key != null) {
final ChannelContext context = (ChannelContext) key.attachment(); final boolean isWrite = key.isWritable();
final SelectableChannel channel = key.channel(); final ChannelContext context = (ChannelContext) key.attachment();
final SelectableChannel channel = key.channel();
if(channel instanceof ServerSocketChannel) { if(channel instanceof ServerSocketChannel) {
try { try {
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) channel; ServerSocketChannel serverSocketChannel = (ServerSocketChannel) channel;
SocketChannel socketChannel = serverSocketChannel.accept(); SocketChannel socketChannel = serverSocketChannel.accept();
ServerSocketContext serverSocketContext = (ServerSocketContext) context; ServerSocketContext serverSocketContext = (ServerSocketContext) context;
SocketContext socketContext = new SocketContext(serverSocketContext); SocketContext socketContext = new SocketContext(serverSocketContext);
socketChannel.configureBlocking(false); socketChannel.configureBlocking(false);
socketChannel.socket().setSendBufferSize(SEND_BUFFER_SIZE); socketChannel.socket().setSendBufferSize(SEND_BUFFER_SIZE);
socketChannel.socket().setReceiveBufferSize(RECEIVE_BUFFER_SIZE); socketChannel.socket().setReceiveBufferSize(RECEIVE_BUFFER_SIZE);
socketContext.key = socketChannel.register(selector, SelectionKey.OP_READ, socketContext); socketContext.key = socketChannel.register(selector, SelectionKey.OP_READ, socketContext);
socketContext.serverSocketContext = serverSocketContext; socketContext.serverSocketContext = serverSocketContext;
//Debug.log("Connection opened to " + socketChannel.socket().getInetAddress() + ":" + socketChannel.socket().getPort()); //Debug.log("Connection opened to " + socketChannel.socket().getInetAddress() + ":" + socketChannel.socket().getPort());
if(serverSocketContext.serviceListener.type != IServiceListener.TYPE_SSL) { if(serverSocketContext.serviceListener.type != IServiceListener.TYPE_SSL) {
socketContext.socketReadBuffer = ByteBuffer.allocate(BUFFER_SIZE); socketContext.socketReadBuffer = ByteBuffer.allocate(BUFFER_SIZE);
}//if//
if(debug) {
Debug.log("Connection opened to " + socketChannel.socket().getInetAddress() + ":" + socketChannel.socket().getPort());
}//if//
}//try//
catch(Throwable e) {
//TODO: Can we recover?
Debug.log(e);
}//catch//
}//if//
else if(channel instanceof SocketChannel) {
// boolean socketClosed = false;
//Toggle the write or read flag.//
synchronized(key) {
// //Save the ops that will be set when the processing is complete.//
// ((AbstractSocketContext) context).setFlags(key.interestOps());
//Notes: Java (pre-jdk7) does not have the ability to read and write to a socket at the same time (two threads, one socket). Post jdk7 there is AsynchronousSocketChannel and AsynchronousServerSocketChannel which could be used to send/receive at the same time.
//Truely enabling Speedy would require a thread to read which when finished would flag read again BEFORE processing the message and BEFORE sending a response.
//For now (so we don't have to require jdk7 yet) we will simply allow Speedy to queue up messages, but only read, process, and then write them one at a time. Most of the speed loss is in the waiting for the WRITE to finish before handling the next request (due to it being broken into packets and the mechanics of TCP), and that is generally minimal (speed lose) since usually the bottleneck in speed is the browser's connection to the internet (most of us haven't got Gigabit Ethernet at home). Anyone with enough home juice to have this be a problem would only notice the difference for really porky websites (which is a problem in and of its self).
key.interestOps(key.interestOps() ^ (isWrite ? SelectionKey.OP_WRITE : SelectionKey.OP_READ));
//Not allowing either reads or writes to continue until all processing of this message is done.//
// key.interestOps(0);
}//synchronized//
if(((SocketChannel) channel).isOpen()) {
ThreadService.run(new Runnable() {
public void run() {
boolean socketClosed = false;
try {
if(isWrite) {
//Prevent another thread from reading/writing on the same socket at the same time (safety). This would have to be removed if SPEEDY (or similar pipelining) were allowed, and AsynchronousSocketChannel/AsynchronousServerSocketChannel would have to be used (requiring jdk7).//
synchronized(((AbstractSocketContext) context).getLock()) {
//Process the pending write to the socket as much as is possible, then return.//
((AbstractSocketContext) context).processResponses();
}//synchronized//
}//if//
else {
//Prevent another thread from reading/writing on the same socket at the same time (safety). This would have to be removed if SPEEDY (or similar pipelining) were allowed, and AsynchronousSocketChannel/AsynchronousServerSocketChannel would have to be used (requiring jdk7).//
synchronized(((AbstractSocketContext) context).getLock()) {
//Process the incoming request and send the response (a partial response may be sent in which case the socket will be set to wait for a write opportunity and not a read opportunity).//
((AbstractSocketContext) context).processRequest();
}//synchronized//
}//else//
}//try//
catch(TlsFailureException e) {
//Allow the failure to be ignored. This occurs when the client fails to use TLS or fails to send the host name as part of the TLS handshake.//
try {((SocketChannel) channel).close();}catch(Throwable e2) {} //Release the socket so the message doesn't continue to be processed.//
}//catch//
catch(Throwable e) {
if(debug) Debug.log(e);
//Force the socket to be closed (for sure).//
try {((SocketChannel) channel).close();} catch(Throwable e2) {}
//Debug.log(e);
socketClosed = true;
}//catch//
finally {
if(channel != null && !socketClosed && channel.isOpen() && context != null) {
selector.wakeup();
}//if//
else if(channel != null && (!channel.isOpen() || socketClosed) && channel instanceof SocketChannel && context instanceof SocketContext) {
cleanupClientChannel((SocketContext) context, (SocketChannel) channel);
}//else if//
}//finally//
}//run()//
});
/*
try {
synchronized(this) {
// if(++activeThreadCount != maxThreadCount) {
//Start another thread to take this thread's place.//
ThreadService.run(this);
// }//if//
}//synchronized//
if(isWrite) {
// if(debug) {
// ((SocketContext) context).debugBuffer.append("Socket is now write available.\n");
// Debug.log("Socket is write available: " + ((SocketChannel) channel).socket().getInetAddress() + ":" + ((SocketChannel) channel).socket().getPort());
// }//if//
//Prevent another thread from reading/writing on the same socket at the same time (safety). This would have to be removed if SPEEDY (or similar pipelining) were allowed, and AsynchronousSocketChannel/AsynchronousServerSocketChannel would have to be used (requiring jdk7).//
synchronized(((AbstractSocketContext) context).getLock()) {
//Process the pending write to the socket as much as is possible, then return.//
((AbstractSocketContext) context).processResponses();
}//synchronized//
}//if// }//if//
else {
// if(debug) {
// ((SocketContext) context).debugBuffer.append("Socket is now read available.\n");
// Debug.log("Socket is read available: " + ((SocketChannel) channel).socket().getInetAddress() + ":" + ((SocketChannel) channel).socket().getPort());
// }//if//
//Prevent another thread from reading/writing on the same socket at the same time (safety). This would have to be removed if SPEEDY (or similar pipelining) were allowed, and AsynchronousSocketChannel/AsynchronousServerSocketChannel would have to be used (requiring jdk7).// if(debug) {
synchronized(((AbstractSocketContext) context).getLock()) { Debug.log("Connection opened to " + socketChannel.socket().getInetAddress() + ":" + socketChannel.socket().getPort());
//Process the incoming request and send the response (a partial response may be sent in which case the socket will be set to wait for a write opportunity and not a read opportunity).// }//if//
((AbstractSocketContext) context).processRequest();
}//synchronized//
}//else//
}//try// }//try//
catch(TlsFailureException e) {
//Allow the failure to be ignored. This occurs when the client fails to use TLS or fails to send the host name as part of the TLS handshake.//
try {((SocketChannel) channel).close();}catch(Throwable e2) {} //Release the socket so the message doesn't continue to be processed.//
}//catch//
catch(Throwable e) { catch(Throwable e) {
if(debug) Debug.log(e); //TODO: Can we recover?
Debug.log(e);
//Force the socket to be closed (for sure).//
try {((SocketChannel) channel).close();}catch(Throwable e2) {}
//Debug.log(e);
socketClosed = true;
}//catch// }//catch//
finally {
boolean requiresWakeup = false;
if(channel != null && !socketClosed && channel.isOpen() && key != null && context != null) {
requiresWakeup = true;
}//if//
else if(channel != null && (!channel.isOpen() || socketClosed) && channel instanceof SocketChannel && context instanceof SocketContext) {
cleanupClientChannel((SocketContext) context, (SocketChannel) channel);
}//else if//
//Loop if the last thread to wait for a message couldn't start another thread due to the max number of threads allowed.//
synchronized(this) {
// if(activeThreadCount-- != maxThreadCount) {
loop = false;
if(requiresWakeup) {
selector.wakeup();
}//if//
// }//if//
}//synchronized//
}//finally//
*/
}//if// }//if//
}//else if// else if(channel instanceof SocketChannel) {
}//if// // boolean socketClosed = false;
//Toggle the write or read flag.//
synchronized(key) {
// //Save the ops that will be set when the processing is complete.//
// ((AbstractSocketContext) context).setFlags(key.interestOps());
//Notes: Java (pre-jdk7) does not have the ability to read and write to a socket at the same time (two threads, one socket). Post jdk7 there is AsynchronousSocketChannel and AsynchronousServerSocketChannel which could be used to send/receive at the same time.
//Truely enabling Speedy would require a thread to read which when finished would flag read again BEFORE processing the message and BEFORE sending a response.
//For now (so we don't have to require jdk7 yet) we will simply allow Speedy to queue up messages, but only read, process, and then write them one at a time. Most of the speed loss is in the waiting for the WRITE to finish before handling the next request (due to it being broken into packets and the mechanics of TCP), and that is generally minimal (speed lose) since usually the bottleneck in speed is the browser's connection to the internet (most of us haven't got Gigabit Ethernet at home). Anyone with enough home juice to have this be a problem would only notice the difference for really porky websites (which is a problem in and of its self).
key.interestOps(key.interestOps() ^ (isWrite ? SelectionKey.OP_WRITE : SelectionKey.OP_READ));
//Not allowing either reads or writes to continue until all processing of this message is done.//
// key.interestOps(0);
}//synchronized//
if(((SocketChannel) channel).isOpen()) {
ThreadService.run(new Runnable() {
public void run() {
boolean socketClosed = false;
try {
if(isWrite) {
//Prevent another thread from reading/writing on the same socket at the same time (safety). This would have to be removed if SPEEDY (or similar pipelining) were allowed, and AsynchronousSocketChannel/AsynchronousServerSocketChannel would have to be used (requiring jdk7).//
synchronized(((AbstractSocketContext) context).getLock()) {
//Process the pending write to the socket as much as is possible, then return.//
((AbstractSocketContext) context).processResponses();
}//synchronized//
}//if//
else {
//Prevent another thread from reading/writing on the same socket at the same time (safety). This would have to be removed if SPEEDY (or similar pipelining) were allowed, and AsynchronousSocketChannel/AsynchronousServerSocketChannel would have to be used (requiring jdk7).//
synchronized(((AbstractSocketContext) context).getLock()) {
//Process the incoming request and send the response (a partial response may be sent in which case the socket will be set to wait for a write opportunity and not a read opportunity).//
((AbstractSocketContext) context).processRequest();
}//synchronized//
}//else//
}//try//
catch(TlsFailureException e) {
//Allow the failure to be ignored. This occurs when the client fails to use TLS or fails to send the host name as part of the TLS handshake.//
try {((SocketChannel) channel).close();}catch(Throwable e2) {} //Release the socket so the message doesn't continue to be processed.//
}//catch//
catch(Throwable e) {
if(debug) Debug.log(e);
//Force the socket to be closed (for sure).//
try {((SocketChannel) channel).close();} catch(Throwable e2) {}
//Debug.log(e);
socketClosed = true;
}//catch//
finally {
if(channel != null && !socketClosed && channel.isOpen() && context != null) {
selector.wakeup();
}//if//
else if(channel != null && (!channel.isOpen() || socketClosed) && channel instanceof SocketChannel && context instanceof SocketContext) {
cleanupClientChannel((SocketContext) context, (SocketChannel) channel);
}//else if//
}//finally//
}//run()//
});
/*
try {
synchronized(this) {
// if(++activeThreadCount != maxThreadCount) {
//Start another thread to take this thread's place.//
ThreadService.run(this);
// }//if//
}//synchronized//
if(isWrite) {
// if(debug) {
// ((SocketContext) context).debugBuffer.append("Socket is now write available.\n");
// Debug.log("Socket is write available: " + ((SocketChannel) channel).socket().getInetAddress() + ":" + ((SocketChannel) channel).socket().getPort());
// }//if//
//Prevent another thread from reading/writing on the same socket at the same time (safety). This would have to be removed if SPEEDY (or similar pipelining) were allowed, and AsynchronousSocketChannel/AsynchronousServerSocketChannel would have to be used (requiring jdk7).//
synchronized(((AbstractSocketContext) context).getLock()) {
//Process the pending write to the socket as much as is possible, then return.//
((AbstractSocketContext) context).processResponses();
}//synchronized//
}//if//
else {
// if(debug) {
// ((SocketContext) context).debugBuffer.append("Socket is now read available.\n");
// Debug.log("Socket is read available: " + ((SocketChannel) channel).socket().getInetAddress() + ":" + ((SocketChannel) channel).socket().getPort());
// }//if//
//Prevent another thread from reading/writing on the same socket at the same time (safety). This would have to be removed if SPEEDY (or similar pipelining) were allowed, and AsynchronousSocketChannel/AsynchronousServerSocketChannel would have to be used (requiring jdk7).//
synchronized(((AbstractSocketContext) context).getLock()) {
//Process the incoming request and send the response (a partial response may be sent in which case the socket will be set to wait for a write opportunity and not a read opportunity).//
((AbstractSocketContext) context).processRequest();
}//synchronized//
}//else//
}//try//
catch(TlsFailureException e) {
//Allow the failure to be ignored. This occurs when the client fails to use TLS or fails to send the host name as part of the TLS handshake.//
try {((SocketChannel) channel).close();}catch(Throwable e2) {} //Release the socket so the message doesn't continue to be processed.//
}//catch//
catch(Throwable e) {
if(debug) Debug.log(e);
//Force the socket to be closed (for sure).//
try {((SocketChannel) channel).close();}catch(Throwable e2) {}
//Debug.log(e);
socketClosed = true;
}//catch//
finally {
boolean requiresWakeup = false;
if(channel != null && !socketClosed && channel.isOpen() && key != null && context != null) {
requiresWakeup = true;
}//if//
else if(channel != null && (!channel.isOpen() || socketClosed) && channel instanceof SocketChannel && context instanceof SocketContext) {
cleanupClientChannel((SocketContext) context, (SocketChannel) channel);
}//else if//
//Loop if the last thread to wait for a message couldn't start another thread due to the max number of threads allowed.//
synchronized(this) {
// if(activeThreadCount-- != maxThreadCount) {
loop = false;
if(requiresWakeup) {
selector.wakeup();
}//if//
// }//if//
}//synchronized//
}//finally//
*/
}//if//
}//else if//
}//if//
}//try//
catch(java.nio.channels.CancelledKeyException e) {
//Occurs if the socket is closed while we are handling the key.//
Debug.log(e); //TODO: Does anything need doing here? Should it be ignored?
}//catch//
catch(Throwable e) {
Debug.log(e);
//TODO: There needs to be more specfic error handling if we got here.
}//catch//
}//while// }//while//
}//run()// }//run()//
}//NetworkListener// }//NetworkListener//

View File

@@ -12,8 +12,6 @@
<classpathentry combineaccessrules="false" kind="src" path="/Foundation TCV"/> <classpathentry combineaccessrules="false" kind="src" path="/Foundation TCV"/>
<classpathentry combineaccessrules="false" kind="src" path="/Foundation TCV Server"/> <classpathentry combineaccessrules="false" kind="src" path="/Foundation TCV Server"/>
<classpathentry combineaccessrules="false" kind="src" path="/Foundation Web Application"/> <classpathentry combineaccessrules="false" kind="src" path="/Foundation Web Application"/>
<classpathentry combineaccessrules="false" kind="src" path="/Foundation Transaction MySQL"/>
<classpathentry combineaccessrules="false" kind="src" path="/MySQL ConnectorJ"/>
<classpathentry kind="lib" path="activation.jar"/> <classpathentry kind="lib" path="activation.jar"/>
<classpathentry kind="lib" path="mail.jar"/> <classpathentry kind="lib" path="mail.jar"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>

View File

@@ -16,13 +16,13 @@ import com.common.util.*;
import com.common.util.optimized.IntHashSet; import com.common.util.optimized.IntHashSet;
import com.common.comparison.Comparator; import com.common.comparison.Comparator;
import com.common.debug.*; import com.common.debug.*;
import com.common.metadata.MetadataContainer;
import com.common.orb.Orb; import com.common.orb.Orb;
import com.foundation.metadata.*; import com.foundation.metadata.*;
import com.foundation.util.ITrackedCollection; import com.foundation.util.ITrackedCollection;
import com.foundation.common.AttributeBinding; import com.foundation.common.AttributeBinding;
import com.foundation.common.EntityMetadata; import com.foundation.common.EntityMetadata;
import com.foundation.common.IEntity; import com.foundation.common.IEntity;
import com.foundation.common.MetadataContainer;
import com.foundation.event.*; import com.foundation.event.*;
import com.foundation.event.model.CollectionBinding; import com.foundation.event.model.CollectionBinding;
import com.foundation.event.model.ModelListener; import com.foundation.event.model.ModelListener;

View File

@@ -7,10 +7,10 @@
*/ */
package com.foundation.attribute; package com.foundation.attribute;
import com.common.metadata.MetadataContainer;
import com.common.orb.Orb; import com.common.orb.Orb;
import com.common.thread.Monitor; import com.common.thread.Monitor;
import com.common.util.LiteList; import com.common.util.LiteList;
import com.foundation.common.MetadataContainer;
import com.foundation.metadata.MetadataService; import com.foundation.metadata.MetadataService;
/** /**

View File

@@ -9,12 +9,12 @@ package com.foundation.attribute;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import com.common.metadata.MetadataContainer;
import com.common.orb.*; import com.common.orb.*;
import com.common.util.*; import com.common.util.*;
import com.common.util.optimized.IntArray; import com.common.util.optimized.IntArray;
import com.common.debug.*; import com.common.debug.*;
import com.foundation.common.IEntity; import com.foundation.common.IEntity;
import com.foundation.common.MetadataContainer;
import com.foundation.exception.ReflectionSynchronizationException; import com.foundation.exception.ReflectionSynchronizationException;
import com.foundation.transaction.Transaction; import com.foundation.transaction.Transaction;
import com.foundation.transaction.TransactionContextHolder; import com.foundation.transaction.TransactionContextHolder;

View File

@@ -7,7 +7,7 @@
*/ */
package com.foundation.attribute; package com.foundation.attribute;
import com.foundation.common.MetadataContainer; import com.common.metadata.MetadataContainer;
public class ReflectRegistrationData implements java.io.Externalizable { public class ReflectRegistrationData implements java.io.Externalizable {
public static byte OPTIONS_NONE = 0x00; public static byte OPTIONS_NONE = 0x00;

View File

@@ -14,11 +14,11 @@ import java.io.ObjectOutput;
import com.common.util.*; import com.common.util.*;
import com.common.util.optimized.IntObjectHashMap; import com.common.util.optimized.IntObjectHashMap;
import com.common.util.optimized.LongObjectHashMap; import com.common.util.optimized.LongObjectHashMap;
import com.common.metadata.MetadataContainer;
import com.common.orb.*; import com.common.orb.*;
import com.common.thread.*; import com.common.thread.*;
import com.common.debug.*; import com.common.debug.*;
import com.foundation.common.IEntity; import com.foundation.common.IEntity;
import com.foundation.common.MetadataContainer;
import com.foundation.event.CustomRequestHandler; import com.foundation.event.CustomRequestHandler;
import com.foundation.event.IRequestHandler; import com.foundation.event.IRequestHandler;
import com.foundation.exception.ReflectionSynchronizationException; import com.foundation.exception.ReflectionSynchronizationException;

View File

@@ -7,8 +7,8 @@
*/ */
package com.foundation.attribute; package com.foundation.attribute;
import com.common.metadata.MetadataContainer;
import com.common.orb.*; import com.common.orb.*;
import com.foundation.common.MetadataContainer;
/** /**
* Used by the reflection support classes to pair the reflection handler with an index. * Used by the reflection support classes to pair the reflection handler with an index.

View File

@@ -7,7 +7,7 @@
*/ */
package com.foundation.clone; package com.foundation.clone;
import com.foundation.common.MetadataContainer; import com.common.metadata.MetadataContainer;
import com.foundation.metadata.CloneContext; import com.foundation.metadata.CloneContext;
public interface ICloneable extends Cloneable { public interface ICloneable extends Cloneable {

View File

@@ -16,8 +16,14 @@ import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import com.common.metadata.MetadataContainer;
import com.common.orb.*; import com.common.orb.*;
import com.common.util.*; import com.common.util.*;
import com.common.util.json.IJsonContext;
import com.common.util.json.JSONArray;
import com.common.util.json.JSONException;
import com.common.util.json.JSONObject;
import com.common.util.json.JSONString;
import com.common.util.optimized.IIntIterator; import com.common.util.optimized.IIntIterator;
import com.common.util.optimized.IntHashSet; import com.common.util.optimized.IntHashSet;
import com.common.comparison.Comparator; import com.common.comparison.Comparator;
@@ -50,10 +56,6 @@ import com.foundation.model.LogicalObjectChangeLog;
import com.foundation.model.VersionedModel; import com.foundation.model.VersionedModel;
import com.foundation.util.IKeyExtractor; import com.foundation.util.IKeyExtractor;
import com.foundation.util.ITrackedCollection; import com.foundation.util.ITrackedCollection;
import com.foundation.util.json.JSONArray;
import com.foundation.util.json.JSONException;
import com.foundation.util.json.JSONObject;
import com.foundation.util.json.JSONString;
public abstract class Entity implements IEntity, ICloneable { public abstract class Entity implements IEntity, ICloneable {
static final long serialVersionUID = -7739741506125052482L; static final long serialVersionUID = -7739741506125052482L;
@@ -1662,62 +1664,18 @@ public boolean equalsEquals(Object object) {
return result; return result;
}//equalsEquals()// }//equalsEquals()//
/** /* (non-Javadoc)
* Converts the entity into a compact JSON string. * @see com.common.util.json.IJsonAware#toJson(com.common.util.json.IJsonContext)
* Includes all attributes that are not cyclical.
* @return The JSON formatted string for the tree of objects.
*/ */
public String toJson() { public void toJson(IJsonContext context) {
return toJson(null, null);
}//toJson()//
/**
* Converts the entity into a JSON string.
* Includes all attributes that are not cyclical.
* @param indent The indent string to be used, or null if spacing should be minimized.
* @return The JSON formatted string for the tree of objects.
*/
public String toJson(String indent) {
return toJson(null, indent);
}//toJson()//
/**
* Converts the entity into a compact JSON string.
* Includes all attributes that are not cyclical.
* @param metadataContainer The container containing metadata on what to include in the JSON.
* @return The JSON formatted string for the tree of objects.
*/
public String toJson(MetadataContainer metadataContainer) {
return toJson(metadataContainer, null);
}//toJson()//
/**
* Converts the entity into a JSON string.
* Includes all attributes that are not cyclical.
* @param metadataContainer The container containing metadata on what to include in the JSON.
* @param indent The indent string to be used, or null if spacing should be minimized.
* @return The JSON formatted string for the tree of objects.
*/
public String toJson(MetadataContainer metadataContainer, String indent) {
StringWriter writer = new StringWriter(10000);
toJson(metadataContainer, indent, 0, new LiteHashSet(100, Comparator.getIdentityComparator(), LiteHashSet.STYLE_NO_DUPLICATES), writer);
return writer.toString();
}//toJson()//
/**
* Converts the entity into a JSON string.
* Includes all attributes that are not cyclical.
* @param metadataContainer The container containing metadata on what to include in the JSON.
* @param indent The indent string to be used, or null if spacing should be minimized.
* @param indentCount The number of indents currently being applied to the output.
* @param included The set of included objects, used to prevent recursion.
* @param writer The writer used to write the output.
*/
public void toJson(MetadataContainer metadataContainer, String indent, int indentCount, LiteHashSet included, StringWriter writer) {
try { try {
boolean commaPrefix = false; boolean commaPrefix = false;
EntityMetadata metadata = (EntityMetadata) metadataContainer.getMetadata(getClass()); EntityMetadata metadata = (EntityMetadata) context.getMetadataContainer().getMetadata(getClass());
IntHashSet metadataAttributes = null; IntHashSet metadataAttributes = null;
IIntIterator metadataAttributeIterator = null; IIntIterator metadataAttributeIterator = null;
int count; int count;
LiteHashSet included = context.getIncluded();
StringWriter writer = context.getWriter();
//Use the metadata provided if any.// //Use the metadata provided if any.//
if(metadata != null) { if(metadata != null) {
@@ -1776,7 +1734,6 @@ public void toJson(MetadataContainer metadataContainer, String indent, int inden
}//if// }//if//
}//for// }//for//
indentCount++;
metadataAttributeIterator.resetToFront(); metadataAttributeIterator.resetToFront();
//Add the actual attributes and values to the JSON output.// //Add the actual attributes and values to the JSON output.//
@@ -1792,13 +1749,7 @@ public void toJson(MetadataContainer metadataContainer, String indent, int inden
writer.write(','); writer.write(',');
}//if// }//if//
if(indent != null) { context.writeNewLine();
writer.write('\n');
for(int indentCounter = 0; indentCounter < indentCount; indentCounter++) {
writer.write(indent);
}//for//
}//if//
//Note: No need to escape things since attribute names only allow A-z and underscore.// //Note: No need to escape things since attribute names only allow A-z and underscore.//
writer.write('"'); writer.write('"');
@@ -1806,26 +1757,18 @@ public void toJson(MetadataContainer metadataContainer, String indent, int inden
writer.write('"'); writer.write('"');
writer.write(':'); writer.write(':');
if(indent != null) { if(!context.isCompact()) {
writer.write(' '); writer.write(' ');
}//if// }//if//
//Write the value out.// //Write the value out.//
jsonValue(value, metadataContainer, indent, indentCount, included, writer); context.toJson(value);
commaPrefix = true; commaPrefix = true;
}//if// }//if//
}//for// }//for//
indentCount--; context.writeNewLine();
if(indent != null) {
writer.write('\n');
for(int indentCounter = 0; indentCounter < indentCount; indentCounter++) {
writer.write(indent);
}//for//
}//if//
}//if// }//if//
writer.write('}'); writer.write('}');
@@ -1834,545 +1777,6 @@ public void toJson(MetadataContainer metadataContainer, String indent, int inden
Debug.log(e); Debug.log(e);
}//catch// }//catch//
}//toJson()// }//toJson()//
/**
* Converts an array of any type of value into a JSON string.
* @param value The collection.
* @param metadataContainer An optional container of metadata identifying which attributes of any class to be included. Classes that are encountered and not specified here will use the default include rules (ignore uninitialized and non-lazy loaded attributes, back references, etc).
* @param indent The optional indent text to be used. Passing null indicates that all extra spacing should be avoided.
* @param indentCount The starting indent count (for pre-indented output). Normally zero (negative values will be assumed to be zero).
* @return The JSON formatted text.
*/
public static String toJson(IHashMap value, MetadataContainer metadataContainer, String indent, int indentCount) {
StringWriter writer = new StringWriter(10000);
try {
toJson(value, metadataContainer, indent, indentCount < 0 ? 0 : indentCount, new LiteHashSet(100, Comparator.getIdentityComparator(), LiteHashSet.STYLE_NO_DUPLICATES), writer);
}//try//
catch(IOException e) {
//Shouldn't ever occur.//
Debug.log(e);
}//catch//
return writer.toString();
}//toJson()//
/**
* Writes an array of values to the JSON stream. This method is intended for internal framework use and is subject to change.
* @param value The collection.
* @param metadataContainer An optional container of metadata identifying which attributes of any class to be included. Classes that are encountered and not specified here will use the default include rules (ignore uninitialized and non-lazy loaded attributes, back references, etc).
* @param indent The optional indent text to be used. Passing null indicates that all extra spacing should be avoided.
* @param indentCount The starting non-negative indent count (for pre-indented output).
* @param included The set of already included values to avoid recursion.
* @param writer The writer used to write the output.
*/
public static void toJson(IHashMap value, MetadataContainer metadataContainer, String indent, int indentCount, LiteHashSet included, StringWriter writer) throws IOException {
writer.write("{");
if(value != null) {
boolean isFirst = true;
for(IIterator iterator = value.keyIterator(); iterator.hasNext(); ) {
Object key = iterator.next();
Object next = value.get(key);
if(!isFirst) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
else {
isFirst = false;
}//else//
if(key != null && !(key instanceof String)) {
key = key.toString();
}//if//
//Just roll over null's by converting them to strings. Better than an error IMO.
if(key == null) {
key = "null";
}//if//
jsonValue(key, metadataContainer, indent, indentCount, included, writer);
writer.write(':');
if(indent != null) {
writer.write(' ');
}//if//
jsonValue(next, metadataContainer, indent, indentCount, included, writer);
}//for//
}//if//
writer.write("}");
}//toJson()//
/**
* Converts an array of any type of value into a JSON string.
* @param value The collection.
* @param metadataContainer An optional container of metadata identifying which attributes of any class to be included. Classes that are encountered and not specified here will use the default include rules (ignore uninitialized and non-lazy loaded attributes, back references, etc).
* @param indent The optional indent text to be used. Passing null indicates that all extra spacing should be avoided.
* @param indentCount The starting indent count (for pre-indented output). Normally zero (negative values will be assumed to be zero).
* @return The JSON formatted text.
*/
public static String toJson(ICollection value, MetadataContainer metadataContainer, String indent, int indentCount) {
StringWriter writer = new StringWriter(10000);
try {
toJson(value, metadataContainer, indent, indentCount < 0 ? 0 : indentCount, new LiteHashSet(100, Comparator.getIdentityComparator(), LiteHashSet.STYLE_NO_DUPLICATES), writer);
}//try//
catch(IOException e) {
//Shouldn't ever occur.//
Debug.log(e);
}//catch//
return writer.toString();
}//toJson()//
/**
* Writes an array of values to the JSON stream. This method is intended for internal framework use and is subject to change.
* @param value The collection.
* @param metadataContainer An optional container of metadata identifying which attributes of any class to be included. Classes that are encountered and not specified here will use the default include rules (ignore uninitialized and non-lazy loaded attributes, back references, etc).
* @param indent The optional indent text to be used. Passing null indicates that all extra spacing should be avoided.
* @param indentCount The starting non-negative indent count (for pre-indented output).
* @param included The set of already included values to avoid recursion.
* @param writer The writer used to write the output.
*/
public static void toJson(ICollection value, MetadataContainer metadataContainer, String indent, int indentCount, LiteHashSet included, StringWriter writer) throws IOException {
writer.write("[");
if(value != null) {
boolean isFirst = true;
for(IIterator iterator = value.iterator(); iterator.hasNext(); ) {
Object next = iterator.next();
if(!isFirst) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
else {
isFirst = false;
}//else//
jsonValue(next, metadataContainer, indent, indentCount, included, writer);
}//for//
}//if//
writer.write("]");
}//toJson()//
/**
* Converts an array of any type of value into a JSON string.
* @param value The collection.
* @param metadataContainer An optional container of metadata identifying which attributes of any class to be included. Classes that are encountered and not specified here will use the default include rules (ignore uninitialized and non-lazy loaded attributes, back references, etc).
* @param indent The optional indent text to be used. Passing null indicates that all extra spacing should be avoided.
* @param indentCount The starting indent count (for pre-indented output). Normally zero (negative values will be assumed to be zero).
* @return The JSON formatted text.
*/
public static String toJson(Map value, MetadataContainer metadataContainer, String indent, int indentCount) {
StringWriter writer = new StringWriter(10000);
try {
toJson(value, metadataContainer, indent, indentCount < 0 ? 0 : indentCount, new LiteHashSet(100, Comparator.getIdentityComparator(), LiteHashSet.STYLE_NO_DUPLICATES), writer);
}//try//
catch(IOException e) {
//Shouldn't ever occur.//
Debug.log(e);
}//catch//
return writer.toString();
}//toJson()//
/**
* Writes an array of values to the JSON stream. This method is intended for internal framework use and is subject to change.
* @param value The collection.
* @param metadataContainer An optional container of metadata identifying which attributes of any class to be included. Classes that are encountered and not specified here will use the default include rules (ignore uninitialized and non-lazy loaded attributes, back references, etc).
* @param indent The optional indent text to be used. Passing null indicates that all extra spacing should be avoided.
* @param indentCount The starting non-negative indent count (for pre-indented output).
* @param included The set of already included values to avoid recursion.
* @param writer The writer used to write the output.
*/
public static void toJson(Map value, MetadataContainer metadataContainer, String indent, int indentCount, LiteHashSet included, StringWriter writer) throws IOException {
writer.write("{");
if(value != null) {
boolean isFirst = true;
for(Iterator iterator = value.keySet().iterator(); iterator.hasNext(); ) {
Object key = iterator.next();
Object next = value.get(key);
if(!isFirst) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
else {
isFirst = false;
}//else//
if(key != null && !(key instanceof String)) {
key = key.toString();
}//if//
//Just roll over null's by converting them to strings. Better than an error IMO.
if(key == null) {
key = "null";
}//if//
jsonValue(key, metadataContainer, indent, indentCount, included, writer);
writer.write(':');
if(indent != null) {
writer.write(' ');
}//if//
jsonValue(next, metadataContainer, indent, indentCount, included, writer);
}//for//
}//if//
writer.write("}");
}//toJson()//
/**
* Converts an array of any type of value into a JSON string.
* @param value The collection.
* @param metadataContainer An optional container of metadata identifying which attributes of any class to be included. Classes that are encountered and not specified here will use the default include rules (ignore uninitialized and non-lazy loaded attributes, back references, etc).
* @param indent The optional indent text to be used. Passing null indicates that all extra spacing should be avoided.
* @param indentCount The starting indent count (for pre-indented output). Normally zero (negative values will be assumed to be zero).
* @return The JSON formatted text.
*/
public static String toJson(Collection value, MetadataContainer metadataContainer, String indent, int indentCount) {
StringWriter writer = new StringWriter(10000);
try {
toJson(value, metadataContainer, indent, indentCount < 0 ? 0 : indentCount, new LiteHashSet(100, Comparator.getIdentityComparator(), LiteHashSet.STYLE_NO_DUPLICATES), writer);
}//try//
catch(IOException e) {
//Shouldn't ever occur.//
Debug.log(e);
}//catch//
return writer.toString();
}//toJson()//
/**
* Writes an array of values to the JSON stream. This method is intended for internal framework use and is subject to change.
* @param value The collection.
* @param metadataContainer An optional container of metadata identifying which attributes of any class to be included. Classes that are encountered and not specified here will use the default include rules (ignore uninitialized and non-lazy loaded attributes, back references, etc).
* @param indent The optional indent text to be used. Passing null indicates that all extra spacing should be avoided.
* @param indentCount The starting non-negative indent count (for pre-indented output).
* @param included The set of already included values to avoid recursion.
* @param writer The writer used to write the output.
*/
public static void toJson(Collection value, MetadataContainer metadataContainer, String indent, int indentCount, LiteHashSet included, StringWriter writer) throws IOException {
writer.write("[");
if(value != null) {
boolean isFirst = true;
for(Iterator iterator = value.iterator(); iterator.hasNext(); ) {
Object next = iterator.next();
if(!isFirst) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
else {
isFirst = false;
}//else//
jsonValue(next, metadataContainer, indent, indentCount, included, writer);
}//for//
}//if//
writer.write("]");
}//toJson()//
/**
* Converts an array of any type of value into a JSON string.
* @param value The array.
* @param metadataContainer An optional container of metadata identifying which attributes of any class to be included. Classes that are encountered and not specified here will use the default include rules (ignore uninitialized and non-lazy loaded attributes, back references, etc).
* @param indent The optional indent text to be used. Passing null indicates that all extra spacing should be avoided.
* @param indentCount The starting indent count (for pre-indented output). Normally zero (negative values will be assumed to be zero).
* @return The JSON formatted text.
*/
public static String toJson(Array value, MetadataContainer metadataContainer, String indent, int indentCount) {
StringWriter writer = new StringWriter(10000);
try {
toJson(value, metadataContainer, indent, indentCount < 0 ? 0 : indentCount, new LiteHashSet(100, Comparator.getIdentityComparator(), LiteHashSet.STYLE_NO_DUPLICATES), writer);
}//try//
catch(IOException e) {
//Shouldn't ever occur.//
Debug.log(e);
}//catch//
return writer.toString();
}//toJson()//
/**
* Writes an array of values to the JSON stream. This method is intended for internal framework use and is subject to change.
* @param value The array.
* @param metadataContainer An optional container of metadata identifying which attributes of any class to be included. Classes that are encountered and not specified here will use the default include rules (ignore uninitialized and non-lazy loaded attributes, back references, etc).
* @param indent The optional indent text to be used. Passing null indicates that all extra spacing should be avoided.
* @param indentCount The starting non-negative indent count (for pre-indented output).
* @param included The set of already included values to avoid recursion.
* @param writer The writer used to write the output.
*/
public static void toJson(Array value, MetadataContainer metadataContainer, String indent, int indentCount, LiteHashSet included, StringWriter writer) throws IOException {
writer.write("[");
if(value != null) {
int length = Array.getLength(value);
Class valueType = value.getClass().getComponentType();
if(valueType.isPrimitive()) {
switch(valueType.getName().charAt(0)) {
case 'Z':
for(int index = 0; index < length; index++) {
if(index > 0) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
writer.write(Array.getBoolean(value, index) ? "true" : "false");
}//for//
break;
case 'C':
for(int index = 0; index < length; index++) {
if(index > 0) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
//TODO: This could be optimized.
jsonQuote("" + Array.getChar(value, index), writer);
}//for//
break;
case 'B':
for(int index = 0; index < length; index++) {
if(index > 0) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
writer.write(Byte.toString(Array.getByte(value, index)));
}//for//
break;
case 'S':
for(int index = 0; index < length; index++) {
if(index > 0) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
writer.write(Short.toString(Array.getShort(value, index)));
}//for//
break;
case 'I':
for(int index = 0; index < length; index++) {
if(index > 0) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
writer.write(Integer.toString(Array.getInt(value, index)));
}//for//
break;
case 'J':
for(int index = 0; index < length; index++) {
if(index > 0) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
writer.write(Long.toString(Array.getLong(value, index)));
}//for//
break;
case 'F':
for(int index = 0; index < length; index++) {
if(index > 0) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
writer.write(Float.toString(Array.getFloat(value, index)));
}//for//
break;
case 'D':
for(int index = 0; index < length; index++) {
if(index > 0) {
writer.write(',');
if(indent != null) {
writer.write(' ');
}//if//
}//if//
writer.write(Double.toString(Array.getDouble(value, index)));
}//for//
break;
}//switch//
}//if//
else {
for(int index = 0; index < length; index++) {
Object next = Array.get(value, index);
jsonValue(next, metadataContainer, indent, indentCount, included, writer);
}//for//
}//else//
}//if//
writer.write("]");
}//toJson()//
/**
* Writes a value to the JSON stream. This method is intended for internal framework use and is subject to change.
* @param value The array.
* @param metadataContainer An optional container of metadata identifying which attributes of any class to be included. Classes that are encountered and not specified here will use the default include rules (ignore uninitialized and non-lazy loaded attributes, back references, etc).
* @param indent The optional indent text to be used. Passing null indicates that all extra spacing should be avoided.
* @param indentCount The starting non-negative indent count (for pre-indented output).
* @param included The set of already included values to avoid recursion.
* @param writer The writer used to write the output.
* @throws IOException
*/
public static void jsonValue(Object value, MetadataContainer metadataContainer, String indent, int indentCount, LiteHashSet included, StringWriter writer) throws IOException {
//Write the value.//
if(value == null || value.equals(null)) {
writer.write("null");
}//if//
else if(value instanceof Entity) {
((Entity) value).toJson(metadataContainer, indent, indentCount, included, writer);
}//else if//
else if(value instanceof ICollection) {
toJson((ICollection) value, metadataContainer, indent, indentCount, included, writer);
}
else if(value instanceof IHashMap) {
toJson((IHashMap) value, metadataContainer, indent, indentCount, included, writer);
}
else if(value instanceof Map) {
toJson((Map) value, metadataContainer, indent, indentCount, included, writer);
}
else if(value instanceof Collection) {
toJson((Collection) value, metadataContainer, indent, indentCount, included, writer);
}
else if(value.getClass().isArray()) {
toJson((Array) value, metadataContainer, indent, indentCount, included, writer);
}
else if(value instanceof Number) {
if(value instanceof Double && (((Double) value).isInfinite() || ((Double) value).isNaN()) || value instanceof Float && (((Float) value).isInfinite() || ((Float) value).isNaN())) {
//TODO: Can we convert the number perhaps? Show a max value or something?
throw new RuntimeException("JSON does not allow non-finite numbers.");
}//if//
String s = value.toString().toLowerCase();
//Remove trailing zeros and the decimal if possible.//
if(s.indexOf('.') > 0 && s.indexOf('e') < 0) {
int sIndex = s.length() - 1;
while(s.charAt(sIndex) == '0') {
sIndex--;
}//while//
if(s.charAt(sIndex) == '.') {
s = s.substring(0, sIndex);
}//if//
else {
s = s.substring(0, sIndex + 1);
}//else//
}//if//
writer.write(s);
}//else if//
else if(value instanceof Boolean) {
writer.write(value.toString());
}//else if//
else if(value instanceof String) {
jsonQuote((String) value, writer);
}//else if//
else {
jsonQuote(value.toString(), writer);
}//else if//
}//jsonValue()//
private static void jsonQuote(String string, Writer w) throws IOException {
if(string == null || string.length() == 0) {
w.write("\"\"");
}
else {
char b;
char c = 0;
String hhhh;
int i;
int len = string.length();
w.write('"');
for(i = 0; i < len; i += 1) {
b = c;
c = string.charAt(i);
switch(c) {
case '\\':
case '"':
w.write('\\');
w.write(c);
break;
case '/':
if(b == '<') {
w.write('\\');
}
w.write(c);
break;
case '\b':
w.write("\\b");
break;
case '\t':
w.write("\\t");
break;
case '\n':
w.write("\\n");
break;
case '\f':
w.write("\\f");
break;
case '\r':
w.write("\\r");
break;
default:
if(c < ' ' || (c >= '\u0080' && c < '\u00a0') || (c >= '\u2000' && c < '\u2100')) {
hhhh = "000" + Integer.toHexString(c);
w.write("\\u" + hhhh.substring(hhhh.length() - 4));
}
else {
w.write(c);
}
}
}
w.write('"');
}//else//
}//jsonQuote()//
/* (non-Javadoc) /* (non-Javadoc)
* @see com.foundation.common.IEntity#getApplication() * @see com.foundation.common.IEntity#getApplication()
*/ */

View File

@@ -13,6 +13,7 @@ import java.io.ObjectOutput;
import com.common.io.IObjectInputStream; import com.common.io.IObjectInputStream;
import com.common.io.IObjectOutputStream; import com.common.io.IObjectOutputStream;
import com.common.metadata.IMetadata;
import com.common.util.IList; import com.common.util.IList;
import com.common.util.optimized.IIntIterator; import com.common.util.optimized.IIntIterator;
import com.common.util.optimized.IntHashSet; import com.common.util.optimized.IntHashSet;

View File

@@ -11,6 +11,7 @@ import java.io.Externalizable;
import com.common.comparison.*; import com.common.comparison.*;
import com.common.io.IExternalizable; import com.common.io.IExternalizable;
import com.common.util.json.IJsonAware;
import com.foundation.attribute.AttributeSupport; import com.foundation.attribute.AttributeSupport;
import com.foundation.attribute.IReflectableObject; import com.foundation.attribute.IReflectableObject;
import com.foundation.application.IApplication; import com.foundation.application.IApplication;
@@ -24,7 +25,7 @@ import com.foundation.transaction.TransactionErrorInfo;
import com.foundation.transaction.Transaction; import com.foundation.transaction.Transaction;
import com.foundation.transaction.TransactionService; import com.foundation.transaction.TransactionService;
public interface IEntity extends IReflectableObject, IEventListener, IEventEmitter, IComparable, IExternalizable, Externalizable { public interface IEntity extends IReflectableObject, IEventListener, IEventEmitter, IComparable, IExternalizable, Externalizable, IJsonAware {
public static final Event VIRTUAL_OBJECT_CHANGED = AttributeSupport.registerEvent(IEntity.class, "virtualObjectChanged"); public static final Event VIRTUAL_OBJECT_CHANGED = AttributeSupport.registerEvent(IEntity.class, "virtualObjectChanged");
/** /**

View File

@@ -7,11 +7,11 @@
*/ */
package com.foundation.metadata; package com.foundation.metadata;
import com.common.metadata.MetadataContainer;
import com.common.util.IIterator; import com.common.util.IIterator;
import com.common.util.LiteHashSet; import com.common.util.LiteHashSet;
import com.common.util.LiteList; import com.common.util.LiteList;
import com.foundation.common.EntityMetadata; import com.foundation.common.EntityMetadata;
import com.foundation.common.MetadataContainer;
import com.foundation.util.IInlineCollectionObserver; import com.foundation.util.IInlineCollectionObserver;
import com.foundation.attribute.AttributeSupport; import com.foundation.attribute.AttributeSupport;

View File

@@ -14,9 +14,9 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import com.common.io.*; import com.common.io.*;
import com.common.metadata.MetadataContainer;
import com.common.util.*; import com.common.util.*;
import com.common.debug.*; import com.common.debug.*;
import com.foundation.common.MetadataContainer;
import com.foundation.metadata.raw.*; import com.foundation.metadata.raw.*;
import com.foundation.util.IKeyExtractor; import com.foundation.util.IKeyExtractor;

View File

@@ -7,10 +7,10 @@
*/ */
package com.foundation.metadata; package com.foundation.metadata;
import com.common.metadata.MetadataContainer;
import com.common.thread.Monitor; import com.common.thread.Monitor;
import com.foundation.attribute.AttributeSupport; import com.foundation.attribute.AttributeSupport;
import com.foundation.common.IEntity; import com.foundation.common.IEntity;
import com.foundation.common.MetadataContainer;
import com.foundation.event.model.ModelListener; import com.foundation.event.model.ModelListener;
/** /**

View File

@@ -7,6 +7,7 @@
*/ */
package com.foundation.util; package com.foundation.util;
import com.common.metadata.MetadataContainer;
import com.common.thread.Monitor; import com.common.thread.Monitor;
import com.common.util.ICollection; import com.common.util.ICollection;
import com.common.util.IHashMap; import com.common.util.IHashMap;
@@ -18,7 +19,6 @@ import com.common.comparison.IComparator;
import com.foundation.attribute.AttributeSupport; import com.foundation.attribute.AttributeSupport;
import com.foundation.common.BackReferenceNode; import com.foundation.common.BackReferenceNode;
import com.foundation.common.IEntity; import com.foundation.common.IEntity;
import com.foundation.common.MetadataContainer;
import com.foundation.metadata.CloneContext; import com.foundation.metadata.CloneContext;
import com.foundation.metadata.ISupportsContainment; import com.foundation.metadata.ISupportsContainment;
import com.foundation.metadata.LoadAttributesContext; import com.foundation.metadata.LoadAttributesContext;

View File

@@ -8,13 +8,13 @@
package com.foundation.util; package com.foundation.util;
import com.common.debug.Debug; import com.common.debug.Debug;
import com.common.metadata.MetadataContainer;
import com.common.thread.Monitor; import com.common.thread.Monitor;
import com.common.thread.ThreadService; import com.common.thread.ThreadService;
import com.common.util.*; import com.common.util.*;
import com.foundation.attribute.AttributeSupport; import com.foundation.attribute.AttributeSupport;
import com.foundation.common.BackReferenceNode; import com.foundation.common.BackReferenceNode;
import com.foundation.common.IEntity; import com.foundation.common.IEntity;
import com.foundation.common.MetadataContainer;
import com.foundation.metadata.CloneContext; import com.foundation.metadata.CloneContext;
import com.foundation.metadata.ISupportsContainment; import com.foundation.metadata.ISupportsContainment;
import com.foundation.metadata.LoadAttributesContext; import com.foundation.metadata.LoadAttributesContext;

View File

@@ -9,6 +9,7 @@ package com.foundation.util;
import com.common.debug.*; import com.common.debug.*;
import com.common.exception.*; import com.common.exception.*;
import com.common.metadata.MetadataContainer;
import com.common.thread.Monitor; import com.common.thread.Monitor;
import com.common.thread.ThreadService; import com.common.thread.ThreadService;
import com.common.util.ICollection; import com.common.util.ICollection;
@@ -19,7 +20,6 @@ import com.common.comparison.*;
import com.foundation.attribute.AttributeSupport; import com.foundation.attribute.AttributeSupport;
import com.foundation.common.BackReferenceNode; import com.foundation.common.BackReferenceNode;
import com.foundation.common.IEntity; import com.foundation.common.IEntity;
import com.foundation.common.MetadataContainer;
import com.foundation.metadata.CloneContext; import com.foundation.metadata.CloneContext;
import com.foundation.metadata.ISupportsContainment; import com.foundation.metadata.ISupportsContainment;
import com.foundation.metadata.LoadAttributesContext; import com.foundation.metadata.LoadAttributesContext;

View File

@@ -16,13 +16,13 @@ import com.common.debug.Debug;
import com.common.event.BooleanHandler1; import com.common.event.BooleanHandler1;
import com.common.event.ObjectHandler1; import com.common.event.ObjectHandler1;
import com.common.event.VoidHandler1; import com.common.event.VoidHandler1;
import com.common.metadata.MetadataContainer;
import com.common.thread.Monitor; import com.common.thread.Monitor;
import com.common.thread.ThreadService; import com.common.thread.ThreadService;
import com.common.util.*; import com.common.util.*;
import com.foundation.attribute.AttributeSupport; import com.foundation.attribute.AttributeSupport;
import com.foundation.common.BackReferenceNode; import com.foundation.common.BackReferenceNode;
import com.foundation.common.IEntity; import com.foundation.common.IEntity;
import com.foundation.common.MetadataContainer;
import com.foundation.metadata.CloneContext; import com.foundation.metadata.CloneContext;
import com.foundation.metadata.ISupportsContainment; import com.foundation.metadata.ISupportsContainment;
import com.foundation.metadata.LoadAttributesContext; import com.foundation.metadata.LoadAttributesContext;

View File

@@ -10,6 +10,7 @@ package com.foundation.util;
import com.common.util.*; import com.common.util.*;
import com.common.comparison.IComparator; import com.common.comparison.IComparator;
import com.common.debug.*; import com.common.debug.*;
import com.common.metadata.MetadataContainer;
import com.common.orb.Orb; import com.common.orb.Orb;
import com.common.thread.*; import com.common.thread.*;
import com.common.event.BooleanHandler1; import com.common.event.BooleanHandler1;
@@ -19,7 +20,6 @@ import com.common.exception.*;
import com.foundation.attribute.*; import com.foundation.attribute.*;
import com.foundation.common.BackReferenceNode; import com.foundation.common.BackReferenceNode;
import com.foundation.common.IEntity; import com.foundation.common.IEntity;
import com.foundation.common.MetadataContainer;
import com.foundation.event.*; import com.foundation.event.*;
import com.foundation.metadata.Attribute; import com.foundation.metadata.Attribute;
import com.foundation.metadata.CloneContext; import com.foundation.metadata.CloneContext;

View File

@@ -9,6 +9,7 @@ package com.foundation.util;
import com.common.debug.*; import com.common.debug.*;
import com.common.exception.*; import com.common.exception.*;
import com.common.metadata.MetadataContainer;
import com.common.thread.Monitor; import com.common.thread.Monitor;
import com.common.util.ICollection; import com.common.util.ICollection;
import com.common.util.IHashSet; import com.common.util.IHashSet;
@@ -22,7 +23,6 @@ import com.foundation.attribute.AttributeSupport;
import com.foundation.attribute.ReflectCollectionData; import com.foundation.attribute.ReflectCollectionData;
import com.foundation.common.BackReferenceNode; import com.foundation.common.BackReferenceNode;
import com.foundation.common.IEntity; import com.foundation.common.IEntity;
import com.foundation.common.MetadataContainer;
import com.foundation.metadata.CloneContext; import com.foundation.metadata.CloneContext;
import com.foundation.metadata.ISupportsContainment; import com.foundation.metadata.ISupportsContainment;
import com.foundation.metadata.LoadAttributesContext; import com.foundation.metadata.LoadAttributesContext;

View File

@@ -9,13 +9,13 @@ package com.foundation.util;
import java.util.Arrays; import java.util.Arrays;
import com.common.metadata.MetadataContainer;
import com.common.orb.*; import com.common.orb.*;
import com.common.util.*; import com.common.util.*;
import com.common.util.optimized.IntArray; import com.common.util.optimized.IntArray;
import com.common.debug.*; import com.common.debug.*;
import com.common.comparison.*; import com.common.comparison.*;
import com.foundation.attribute.*; import com.foundation.attribute.*;
import com.foundation.common.MetadataContainer;
import com.foundation.exception.ReflectionSynchronizationException; import com.foundation.exception.ReflectionSynchronizationException;
import com.foundation.metadata.CloneContext; import com.foundation.metadata.CloneContext;
import com.foundation.metadata.ISupportsContainment; import com.foundation.metadata.ISupportsContainment;

View File

@@ -3,6 +3,7 @@ package com.foundation.util;
import com.common.comparison.Comparator; import com.common.comparison.Comparator;
import com.common.comparison.IComparator; import com.common.comparison.IComparator;
import com.common.debug.Debug; import com.common.debug.Debug;
import com.common.metadata.MetadataContainer;
import com.common.orb.Orb; import com.common.orb.Orb;
import com.common.util.ICollection; import com.common.util.ICollection;
import com.common.util.IIndexedCollection; import com.common.util.IIndexedCollection;
@@ -16,7 +17,6 @@ import com.foundation.attribute.IReflectUpdateHandler;
import com.foundation.attribute.IReflectable; import com.foundation.attribute.IReflectable;
import com.foundation.attribute.ReflectCollectionData; import com.foundation.attribute.ReflectCollectionData;
import com.foundation.attribute.ReflectionContext; import com.foundation.attribute.ReflectionContext;
import com.foundation.common.MetadataContainer;
import com.foundation.event.EventSupport; import com.foundation.event.EventSupport;
import com.foundation.exception.ReflectionSynchronizationException; import com.foundation.exception.ReflectionSynchronizationException;
import com.foundation.metadata.CloneContext; import com.foundation.metadata.CloneContext;

View File

@@ -8,6 +8,7 @@
package com.foundation.util; package com.foundation.util;
import com.common.comparison.*; import com.common.comparison.*;
import com.common.metadata.MetadataContainer;
import com.common.util.ICollection; import com.common.util.ICollection;
import com.common.util.IHashMap; import com.common.util.IHashMap;
import com.common.util.IIterator; import com.common.util.IIterator;
@@ -15,7 +16,6 @@ import com.common.util.IList;
import com.common.util.LiteList; import com.common.util.LiteList;
import com.common.util.ITree; import com.common.util.ITree;
import com.foundation.attribute.ReflectionContext; import com.foundation.attribute.ReflectionContext;
import com.foundation.common.MetadataContainer;
import com.foundation.metadata.CloneContext; import com.foundation.metadata.CloneContext;
import com.foundation.metadata.LoadAttributesContext; import com.foundation.metadata.LoadAttributesContext;

View File

@@ -1,181 +0,0 @@
package com.foundation.util.json;
import java.io.IOException;
import java.io.StringWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.common.comparison.Comparator;
import com.common.debug.Debug;
import com.common.exception.InvalidArgumentException;
import com.common.util.IIterator;
import com.common.util.LiteHashMap;
import com.common.util.LiteHashSet;
import com.common.util.LiteList;
import com.foundation.common.Entity;
import com.foundation.common.MetadataContainer;
/**
* Reads and writes JSON formatted data.
* Uses hashmaps and lists for the java side data structure.
*/
public class JsonBuilder {
private JsonBuilder() {
}//JsonBuilder()//
private static LiteHashMap readObject(JSONObject object) throws JSONException {
String[] keys = JSONObject.getNames(object);
LiteHashMap result = new LiteHashMap(keys.length > 10 ? keys.length : 10);
for(int index = 0; index < keys.length; index++) {
Object value = object.get(keys[index]);
if(value instanceof JSONObject) {
value = readObject((JSONObject) value);
}//if//
else if(value instanceof JSONArray) {
value = readArray((JSONArray) value);
}//else if//
else if(value == JSONObject.NULL) {
value = null;
}//else if//
result.put(keys[index], value);
}//for//
return result;
}//readObject()//
private static LiteList readArray(JSONArray array) throws JSONException {
LiteList result = new LiteList(array.length() > 10 ? array.length() : 10);
for(int index = 0; index < array.length(); index++) {
Object value = array.get(index);
if(value instanceof JSONObject) {
value = readObject((JSONObject) value);
}//if//
else if(value instanceof JSONArray) {
value = readArray((JSONArray) value);
}//else if//
else if(value == JSONObject.NULL) {
value = null;
}//else if//
result.add(value);
}//for//
return result;
}//readArray()//
/**
* Converts the JSON string into a collection of LiteHashMap and LiteList instances.
* @param json
* @return
*/
public static LiteHashMap readJson(String json) {
try {
JSONTokener tokener = new JSONTokener(json);
//TODO: It may be an array starting the JSON, not an object.
JSONObject object = new JSONObject(tokener);
return readObject(object);
}//try//
catch(JSONException e) {
Debug.log(e);
throw new InvalidArgumentException("Invalid JSON string.");
}//catch//
}//readJson()//
private static JSONObject writeObject(LiteHashMap object) throws JSONException {
JSONObject result = new JSONObject();
for(IIterator iterator = object.keyIterator(); iterator.hasNext(); ) {
String key = (String) iterator.next();
Object value = object.get(key);
if(value instanceof LiteHashMap) {
value = writeObject((LiteHashMap) value);
}//if//
else if(value instanceof LiteList) {
value = writeArray((LiteList) value);
}//else if//
else if(value == null) {
value = JSONObject.NULL;
}//else if//
result.put(key, value);
}//for//
return result;
}//writeObject()//
private static JSONArray writeArray(LiteList array) throws JSONException {
JSONArray result = new JSONArray();
for(int index = 0; index < array.getSize(); index++) {
Object value = array.get(index);
if(value instanceof LiteHashMap) {
value = writeObject((LiteHashMap) value);
}//if//
else if(value instanceof LiteList) {
value = writeArray((LiteList) value);
}//else if//
else if(value == null) {
value = JSONObject.NULL;
}//else if//
result.put(value);
}//for//
return result;
}//writeArray()//
/**
* Converts the value into a compact JSON string.
* Includes all attributes that are not cyclical.
* @param value The value to be converted (it will delve into collections and examine Entity objects to build the JSON string).
* @return The JSON formatted string for the tree of objects.
*/
public static String writeJson(Object value) {
return writeJson(value, null, null);
}//writeJson()//
/**
* Converts the value into a JSON string.
* Includes all attributes that are not cyclical.
* @param indent The indent string to be used, or null if spacing should be minimized.
* @return The JSON formatted string for the tree of objects.
*/
public static String writeJson(Object value, String indent) {
return writeJson(value, null, indent);
}//toJson()//
/**
* Converts the value into a compact JSON string.
* Includes all attributes that are not cyclical.
* @param metadataContainer The container containing metadata on what to include in the JSON.
* @return The JSON formatted string for the tree of objects.
*/
public static String writeJson(Object value, MetadataContainer metadataContainer) {
return writeJson(value, metadataContainer, null);
}//toJson()//
/**
* Converts the value into a JSON string.
* Includes all attributes that are not cyclical.
* @param metadataContainer The container containing metadata on what to include in the JSON.
* @param indent The indent string to be used, or null if spacing should be minimized.
* @return The JSON formatted string for the tree of objects.
*/
public static String writeJson(Object value, MetadataContainer metadataContainer, String indent) {
StringWriter writer = new StringWriter(10000);
if(value != null) {
try {
Entity.jsonValue(value, metadataContainer, indent, 0, new LiteHashSet(100, Comparator.getIdentityComparator(), LiteHashSet.STYLE_NO_DUPLICATES), writer);
}//try//
catch(IOException e) {
//Shouldn't ever occur.//
Debug.log(e);
}//catch//
catch(Throwable e) {
Debug.log(e);
}//catch//
}//if//
return writer.toString();
}//toJson()//
}//JsonBuilder//