/******************************************************************************* * Copyright (c) 2012 IBM Corporation. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v. 1.0 which accompanies this distribution. * * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * * Keith Wells - initial API and implementation * Sam Padgett - initial API and Implementation * Jim Conallen - initial API and implementation * *******************************************************************************/ package org.eclipse.lyo.samples.sharepoint.store; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.lyo.samples.sharepoint.core.IConstants; import org.eclipse.lyo.samples.sharepoint.store.ShareResource; import org.eclipse.lyo.samples.sharepoint.store.ShareServerException; import org.eclipse.lyo.samples.sharepoint.store.ShareStatement; import org.eclipse.lyo.samples.sharepoint.store.ShareValue; import org.eclipse.lyo.samples.sharepoint.util.StringUtils; public class JsonFormatter2 { private ShareResource resource = null; private Map<String,String> namespacePrefixes = new HashMap<String,String>(); private IMultiValueResolver multiValueResolver; public JsonFormatter2( IMultiValueResolver resolver ) { this.multiValueResolver = resolver; } public void addNamespacePrefix(String ns, String prefix) { this.namespacePrefixes.put(ns, prefix); } public String format(ShareResource resource ) throws ShareServerException { this.resource = new ShareResource(resource.getUri()); // make a copy of the resource, that we can modify this.resource.addStatements(resource.getStatements()); initPrefixes(); StringBuffer sb = new StringBuffer(); sb.append("{\n"); sb.append("\t\"" + IConstants.RDF_PTERM_ABOUT + "\" : " + quote(resource.getUri()) ); List<ShareStatement> types = resource.getStatements(resource.getUri(), IConstants.RDF_TYPE, null); appendProperties( sb, IConstants.RDF_TYPE, types ); sb.append(",\n"); addChildren(sb, resource.getUri(), "\t"); // now do prefixes sb.append(",\n\t\"prefixes\": {\n" ); // add prefixes Set<String> namespaces = this.namespacePrefixes.keySet(); boolean first = true; for (String namespace : namespaces) { String prefix = namespacePrefixes.get(namespace); if( first ) { first = false; } else { sb.append(",\n" ); } sb.append( "\t\t\"" + encode(prefix) + "\" : \"" + encode(namespace) + "\""); } sb.append("\n\t}" ); sb.append("\n}"); return sb.toString(); } private void addChildren(StringBuffer sb, String subject, String indent) throws ShareServerException{ boolean first = true; Map<String, List<ShareStatement>> stMap = getStatementsByProperty(subject); Set<String> propSet = stMap.keySet(); for (String prop : propSet) { if( !IConstants.RDF_TYPE.equals(prop) ) { RdfTerm pTerm = new RdfTerm(prop); if( first ) { first = false; } else { sb.append(",\n" ); } List<ShareStatement> props = stMap.get(prop); if( props.size() > 1 || this.isMultiValued(prop) ) { sb.append( indent + "\t\"" + pTerm + "\" : [ \n" ); boolean sFirst = true; for (ShareStatement s : props) { if( sFirst ) { sFirst = false; } else { sb.append(",\n" ); } sb.append( indent + "\t\t" + toJson(s, indent) ); } sb.append( "\n" + indent + "\t]" ); } else { // single valued ShareStatement st = props.get(0); sb.append( indent + "\t\"" + pTerm + "\" : " + toJson(st, indent) ); } } } } private boolean isMultiValued(String property) { if( this.multiValueResolver != null ) { return this.multiValueResolver.isMultiValued(property); } return false; } private Map<String,List<ShareStatement>> getStatementsByProperty(String subject) { Map<String,List<ShareStatement>> statementsForProp = new HashMap<String,List<ShareStatement>>(); List<ShareStatement> statements = resource.getStatements(subject, null, null); for (ShareStatement rioStatement : statements) { if( statementsForProp.containsKey(rioStatement.getPredicate()) ) { statementsForProp.get(rioStatement.getPredicate()).add(rioStatement); } else { // init with new list ArrayList<ShareStatement> list = new ArrayList<ShareStatement>(); list.add(rioStatement); statementsForProp.put(rioStatement.getPredicate(), list); } } return statementsForProp; } private String toJson(ShareStatement rioStatement, String indent) throws ShareServerException { try{ StringBuffer sb = new StringBuffer(); ShareValue value = rioStatement.getObject(); switch( value.getType() ) { case BOOLEAN: { sb.append( rioStatement.getObject().booleanValue() ); break; } case INTEGER: { sb.append( rioStatement.getObject().intValue() ); break; } case DECIMAL: { sb.append( rioStatement.getObject().doubleValue() ); break; } case CALENDAR: { String dStr = StringUtils.xsdDateTime(rioStatement.getObject().dateValue()); sb.append( quote( dStr) ); break; } case XMLLiteral: case STRING: { sb.append( quote( rioStatement.getObject().stringValue()) ); break; } case URI: { sb.append( " { \"rdf:resource\" : " + quote( rioStatement.getObject().stringValue()) + "}"); break; } case BLANK_NODE: { // inlined resource sb.append(indent + "{\n"); addChildren(sb, rioStatement.getObject().stringValue(), indent + "\t"); sb.append("\n" + indent + "}"); // List<ShareStatement> childStatements = this.resource.getStatements(rioStatement.getObject().stringValue(), null, null); // sb.append( "{\n"); // boolean first = true; // for (ShareStatement rs : childStatements) { // String pred = rs.getPredicate(); // if( !IConstants.RDF_TYPE.equals(pred) ) { // RdfTerm pTerm = new RdfTerm(pred); // if( first ) { // first = false; // } else { // sb.append(",\n" ); // } // sb.append( indent + "\t\t\"" + pTerm + "\" : " + toJson(rs, indent+"\t" ) ); // } // } // sb.append( "\n\t" + indent + " }"); break; } } return sb.toString(); } catch( Exception e ) { throw new ShareServerException(e); } } private void appendProperties(StringBuffer sb, String property, List<ShareStatement> statements) throws ShareServerException { RdfTerm term = new RdfTerm( property ); sb.append(",\n\t\"" + term.prefixedTerm() + "\" : [\n" ); boolean first = true; try{ for (ShareStatement rioStatement : statements) { if( first ) { first = false; } else { sb.append(",\n"); } sb.append("\t" + this.toJson(rioStatement, "") ); } } catch( Exception e ) { throw new ShareServerException(e); } sb.append("\n\t]" ); } // private void appendProperty(StringBuffer sb, String property, ShareStatement statement) throws ShareServerException { // RdfTerm term = new RdfTerm( property ); // try{ // sb.append(",\n\t\"" + term.prefixedTerm() + "\" : \"" + this.asJsonValue(statement) + "\"" ); // } catch( Exception e ) { // throw new ShareServerException(e); // } // } private String quote(String str) { return "\"" + encode(str) + "\""; } private String encode(String str) { if( str == null || str.isEmpty() ) { return "\"\""; } StringBuffer sb = new StringBuffer(); int len = str.length(); for(int i=0;i<len;i++) { char c = str.charAt(i); switch (c) { case '\\': sb.append("\\\\"); break; case '"': sb.append("\\\""); break; // case '/': // sb.append("\\/"); // break; case '\b': sb.append("\\b"); break; case '\f': sb.append("\\f"); break; case '\n': sb.append("\\n"); break; case '\r': sb.append("\\r"); break; case '\t': sb.append("\\t"); break; default: if( c < ' ' || (c >= '\u0080' && c < '\u00a0') || (c >= '\u2000' && c < '\u2100') ) { String hexStr = Integer.toHexString(c); int hlen = hexStr.length(); while( hlen < 4 ) { hexStr = '0' + hexStr; hlen = hexStr.length(); } sb.append("\\u" + hexStr ); } else { sb.append(c); } } } return sb.toString(); } private class RdfTerm { public String namespace; public String term; public String prefix; public RdfTerm( String uri ) { int pos = uri.lastIndexOf('#'); if( pos < 0 ) { pos = uri.lastIndexOf('/'); } this.namespace = uri.substring(0,pos+1); this.term = uri.substring(pos+1); this.prefix = getPrefix(namespace); } public String prefixedTerm(){ return prefix + ':' + encode(term); } public String toString(){ return prefixedTerm(); } } private String getPrefix(String namespace) { String prefix = namespacePrefixes.get(namespace); if( prefix == null ) { // then find the next available prefix int i=0; String pre = "pr" + i; //$NON-NLS-1$ Collection<String> prefixes = namespacePrefixes.values(); while( prefixes.contains(pre) ) { i++; pre = "pr" + i; //$NON-NLS-1$ } namespacePrefixes.put(namespace, pre); prefix = pre; } return prefix; } private void initPrefixes() { namespacePrefixes.put(IConstants.RDF_NAMESPACE, IConstants.RDF_PREFIX); namespacePrefixes.put(IConstants.OSLC_NAMESPACE, IConstants.OSLC_PREFIX); namespacePrefixes.put(IConstants.DCTERMS_NAMESPACE, IConstants.DCTERMS_PREFIX); namespacePrefixes.put(IConstants.SHARE_NAMESPACE, IConstants.SHARE_PREFIX); } public interface IMultiValueResolver { public boolean isMultiValued(String property); } }