blob: dd4ce0f990de501486f5e95b3104186a318dff4f [file] [log] [blame]
package org.apache.velocity.tools.generic;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.IOException;
import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
import java.util.Iterator;
import java.util.Set;
import org.apache.velocity.tools.Scope;
import org.apache.velocity.tools.config.DefaultKey;
import org.apache.velocity.tools.config.InvalidScope;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import com.github.cliftonlabs.json_simple.JsonArray;
import com.github.cliftonlabs.json_simple.JsonObject;
import com.github.cliftonlabs.json_simple.Jsoner;
/**
* <p>Tool which can parse a JSON file.</p>
* <p>Usage:</p>
* <ul>
* <li>$json.parse(<i>JSON string</i>)</li>
* <li>$json.read(<i>file or classpath resource</i>)</li>
* <li>$json.fetch(<i>URL</i>)</li>
* </ul>
* <p>Configuration parameters:</p>
* <ul>
* <li><code>resource</code>=<i>file or classpath resource</i></li>
* <li><code>source</code>=<i>URL</i></li>
* </ul>
* <p>Example configuration:</p>
* <pre>
* &lt;tools&gt;
* &lt;toolbox scope="request"&gt;
* &lt;tool class="org.apache.velocity.tools.generic.JsonTool"
* key="foo" resource="doc.xml"/&gt;
* &lt;/toolbox&gt;
* &lt;/tools&gt;
* </pre>
* @author Claude Brisson
* @since VelocityTools 3.0
* @version $Id:$
*/
// JSONObject isn't (yet?) Serializable, so session scope is invalid
@DefaultKey("json")
@InvalidScope(Scope.SESSION)
public class JsonTool extends ImportSupport implements Iterable, Serializable
{
private static final long serialVersionUID = -6239459645862004347L;
/**
* ImportSupport utility which provides underlying i/o
*/
protected transient ImportSupport importSupport = null;
/**
* ImportSupport initialization
* @param config configuration values
*/
protected synchronized void initializeImportSupport(ValueParser config)
{
if (importSupport == null)
{
importSupport = new ImportSupport();
importSupport.configure(config);
}
}
private JsonContent root = null;
/**
* Looks for the "file" parameter and automatically uses
* {@link #initJSON(String)} to parse the file (searched in filesystem current path and classpath) and set the
* resulting JSON object as the root node for this instance.
* @param values configuration values
*/
protected void configure(ValueParser values)
{
super.configure(values);
initializeImportSupport(values);
String resource = values.getString(ImportSupport.RESOURCE_KEY);
if (resource != null)
{
read(resource);
}
else
{
String url = values.getString(ImportSupport.URL_KEY);
if (url != null)
{
/* temporary disable safe mode */
boolean safeMode = importSupport.isSafeMode();
importSupport.setSafeMode(false);
fetch(url);
importSupport.setSafeMode(safeMode);
}
}
}
/**
* Initialize JSON content from a string.
* @param json JSON string
*/
protected void initJSON(String json)
{
if (json != null)
{
initJSON(new StringReader(json));
}
}
/**
* Initialize JSON content from a reader.
* @param reader JSON stream reader
*/
protected void initJSON(Reader reader)
{
try
{
Object result = Jsoner.deserialize(reader);
if (result instanceof JsonObject)
{
root = new JsonContent((JsonObject)result);
}
else if (result instanceof JsonArray)
{
root = new JsonContent((JsonArray)result);
}
else throw new Exception("Expecting JSON array or object");
}
catch (Exception e)
{
getLog().error("error while setting up JSON source", e);
root = null;
}
}
/**
* Parses the given JSON string and uses the resulting {@link Document}
* as the root {@link Node}.
* @param json JSON string
* @return new JsonTool
*/
public JsonTool parse(String json)
{
if (json != null)
{
try
{
initJSON(json);
}
catch (Exception e)
{
getLog().error("could not parse given JSON string", e);
}
}
return this;
}
/**
* Reads and parses a local JSON resource file
* @param resource resource name
* @return new JsonTool
*/
public JsonTool read(String resource)
{
if (resource != null)
{
Reader reader = null;
try
{
if (importSupport == null)
{
initializeImportSupport(new ValueParser());
}
reader = importSupport.getResourceReader(resource);
if (reader != null)
{
initJSON(reader);
}
}
catch (Exception e)
{
getLog().error("could not read JSON resource {}", resource, e);
}
finally
{
if (reader != null)
{
try
{
reader.close();
}
catch (IOException ioe) {}
}
}
}
return this;
}
/**
* Reads and parses a remote or local URL
* @param url resource URL
* @return new JSonTool
*/
public JsonTool fetch(String url)
{
if (url != null)
{
Reader reader = null;
try
{
if (importSupport == null)
{
initializeImportSupport(new ValueParser());
}
reader = importSupport.acquireReader(url);
if (reader != null)
{
initJSON(reader);
}
}
catch (Exception e)
{
getLog().error("could not fetch JSON content from URL {}", url, e);
}
finally
{
if (reader != null)
{
try
{
reader.close();
}
catch (IOException ioe) {}
}
}
}
return this;
}
/**
* Get JSON root object.
* @return root object or array
*/
public Object root()
{
return root;
}
/**
* Get nth element from root json array.
* @param index n
* @return nth element, or null if root object is null or not an array
*/
public Object get(int index)
{
return root == null ? null : root.get(index);
}
/**
* Get a property from root object
* @param key property key
* @return property value, or null
*/
public Object get(String key)
{
return root == null ? null : root.get(key);
}
/**
* Iterate keys of root object.
* @return iterator
*/
public Iterator<String> keys()
{
return root == null ? null : root.keys();
}
/**
* Get set of root object keys.
* @return keys set
*/
public Set<String> keySet()
{
return root == null ? null : root.keySet();
}
/**
* Get an iterator. For a root object, returns an iterator over key names. For a root array, returns an iterator
* over contained objects.
* @return iterator
*/
public Iterator iterator()
{
return root == null ? null : root.iterator();
}
/**
* Get size of root object or array.
* @return size
*/
public int size()
{
return root == null ? null : root.size();
}
/**
* Convert JSON object or array into string
* @return JSON representation of the root object or array
*/
public String toString()
{
return root == null ? null : root.toString();
}
}