/* See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* Esri Inc. 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.
*/
package com.esri.gpt.control.georss;
import com.esri.gpt.catalog.discovery.rest.RestQuery;
import com.esri.gpt.catalog.search.*;
import com.esri.gpt.framework.geometry.Envelope;
import com.esri.gpt.framework.isodate.IsoDateFormat;
import com.esri.gpt.framework.jsf.MessageBroker;
import com.esri.gpt.framework.util.Val;
import java.io.PrintWriter;
import java.util.Date;
/**
* JSON feed writer.
* Writes response in JSON (or pretty JSON) format.
*/
public class JsonFeedWriter implements FeedWriter {
/** tab size */
private final static int TAB_SIZE = 2;
/** ISO date format */
private final static IsoDateFormat DF = new IsoDateFormat();
/** print writer */
private PrintWriter writer;
/** original query */
private RestQuery query;
/** flag indicating if is this a pretty formated JSON */
private boolean pretty;
/** message broker */
private MessageBroker messageBroker;
/** callback */
private String callback = "";
/**
* Creates instance of the feed.
* @param writer writer to write feed
* @param query query
* @param pretty <code>true</code> to print pretty response
*/
public JsonFeedWriter(PrintWriter writer, RestQuery query, boolean pretty) {
this.writer = writer;
this.query = query;
this.pretty = pretty;
}
/** indentation level */
private int level = 0;
@Override
public void write(IFeedRecords records) {
String sTitle = messageBroker.retrieveMessage("catalog.rest.title");
String sDescription = messageBroker.retrieveMessage("catalog.rest.description");
String sCopyright = messageBroker.retrieveMessage("catalog.rest.copyright");
String sGenerator = messageBroker.retrieveMessage("catalog.rest.generator");
if (sTitle.startsWith("???")) sTitle = "";
if (sDescription.startsWith("???")) sDescription = "";
if (sCopyright.startsWith("???")) sCopyright = "";
if (sGenerator.startsWith("???")) sGenerator = "";
if (!getCallback().isEmpty()) {
println(getCallback()+"({");
} else {
println("{");
}
levelUp();
printArg("title", sTitle, true);
printArg("description", sDescription, true);
printArg("copyright", sCopyright, true);
if(query != null){
printArg("provider", query.getRssProviderUrl(), true);
}
printArg("updated", DF.format(new Date()), true);
if(query != null){
printArg("source", query.getRssSourceUrl(), true);
if (records.size()>=query.getFilter().getMaxRecords()) {
printArg("more", query.getMoreUrl(), true);
}
}
OpenSearchProperties osProps = records.getOpenSearchProperties();
if (osProps!=null) {
printArg("totalResults", new Long(osProps.getNumberOfHits()), true);
printArg("startIndex", new Long(osProps.getStartRecord()), true);
printArg("itemsPerPage", new Long(osProps.getRecordsPerPage()), true);
}
printRecords(records, false);
levelDown();
if (!getCallback().isEmpty()) {
println("})");
} else {
println("}");
}
}
/**
* Gets callback.
* @return callback or empty string if no callback
*/
public String getCallback() {
return callback;
}
/**
* Sets callback.
* @param callback callback name
*/
public void setCallback(String callback) {
this.callback = Val.chkStr(callback);
}
/**
* Increases level of indentation.
*/
private void levelUp() {
level++;
}
/**
* Decreases level of indentation.
*/
private void levelDown() {
level--;
}
/**
* Prints all records.
* @param records records to print
* @param more flag to indicate if there will be more arguments
*/
private void printRecords(IFeedRecords records, boolean more) {
println("\"records\"" +sp()+ ":" +sp()+ "[");
levelUp();
for (int i=0; i<records.size(); i++) {
printRecord(records.get(i), i<records.size()-1);
}
levelDown();
println("]"+(more? ",": ""));
}
/**
* Prints record.
* @param r record to print
* @param more flag to indicate if there will be more arguments
*/
private void printRecord(IFeedRecord r, boolean more) {
println("{");
levelUp();
printArg("title", r.getTitle(), true);
printArg("id", r.getUuid(), true);
if (r.getModfiedDate() instanceof Date) {
printArg("updated", DF.format(r.getModfiedDate()), true);
}
printArg("summary", r.getAbstract(), true);
//println("\"bbox\""+sp()+":"+sp()+bbox(r.getEnvelope())+",");
//printGeometry(r.getEnvelope(), true);
printLinks(r.getResourceLinks(), false);
levelDown();
println("}"+(more? ",": ""));
}
/**
* Prints geometry.
* @param env geometry
* @param more flag to indicate if there will be more arguments
*/
private void printGeometry(Envelope env, boolean more) {
println("\"geometry\"" +sp()+ ":" +sp()+ "{");
levelUp();
printArg("type", "Polygon", true);
println("\"coordinates\"" +sp()+ ":" +sp()+ "[");
printPolygon(env);
println("]");
levelDown();
println("}"+(more? ",": ""));
}
/**
* Prints polygon.
* @param env polygon to print
*/
private void printPolygon(Envelope env) {
levelUp();
println("[");
levelUp();
println(
coord(env.getMinX(),env.getMinY())+","+sp() +
coord(env.getMinX(),env.getMaxY())+","+sp() +
coord(env.getMaxX(),env.getMaxY())+","+sp() +
coord(env.getMaxX(),env.getMinY())+","+sp() +
coord(env.getMinX(),env.getMinY())
);
levelDown();
println("]");
levelDown();
}
/**
* Prints all links.
* @param links collection of resource links
* @param more flag to indicate if there will be more arguments
*/
private void printLinks(ResourceLinks links, boolean more) {
println("\"links\"" +sp()+ ":" +sp()+ "[");
levelUp();
if (links.getThumbnail()!=null) {
printLink(links.getThumbnail(), links.size()>0);
}
for (int j = 0; j<links.size(); j++) {
ResourceLink link = links.get(j);
printLink(link, j<links.size()-1);
}
levelDown();
println("]"+(more? ",": ""));
}
/**
* Prints a link.
* @param link resource link
* @param more flag to indicate if there will be more arguments
*/
private void printLink(ResourceLink link, boolean more) {
if (!link.getTag().isEmpty() && !link.getUrl().isEmpty()) {
println("{");
levelUp();
printArg("href", link.getUrl(), true);
printArg("type", link.getTag(), false);
levelDown();
println("}" + (more? ",": ""));
}
}
/**
* Prints argument.
* @param argName argument name
* @param argVal argument value
* @param more flag to indicate if there will be more arguments
*/
private void printArg(String argName, String argVal, boolean more) {
argName = Val.chkStr(argName);
argVal = Val.chkStr(argVal);
if (argName.length()>0) {
println("\"" +argName+ "\"" + sp() + ":" + sp() + "\"" +Val.escapeStrForJson(argVal)+ "\""+(more? ",": ""));
}
}
/**
* Prints argument.
* @param argName argument name
* @param argVal argument value
* @param more flag to indicate if there will be more arguments
*/
private void printArg(String argName, Number argVal, boolean more) {
argName = Val.chkStr(argName);
if (argName.length()>0) {
println("\"" +argName+ "\"" + sp() + ":" + sp() + argVal + (more? ",": ""));
}
}
/**
* Prints a single line. Depending on the 'pretty' flag, line is indencated or not.
* @param text text to print
*/
private void println(String text) {
if (pretty) {
printTab();
writer.println(text);
} else {
writer.print(text);
}
}
/**
* Prints tabulator. Tabulator width depends on the indentation level.
*/
private void printTab() {
for (int i = 0; i < level * TAB_SIZE; i++) {
writer.print(" ");
}
}
/**
* Makes bounding box.
* @param env bounding box
* @return bounding box in JSON format
*/
private String bbox(Envelope env) {
return "[" + Double.toString(env.getMinX()) + "," + sp() + Double.toString(env.getMinY()) + "," + sp() + Double.toString(env.getMaxX()) + "," + sp() + Double.toString(env.getMaxY()) + "]";
}
/**
* Makes coordinates.
* @param x x coordinate
* @param y y coordinate
* @return coordinate in JSON format
*/
private String coord(double x, double y) {
return "[" + Double.toString(x) + "," +Double.toString(y) + "]";
}
/**
* Creates a single space. Depending on the 'pretty' flag, it's either a space or
* no space at all.
* @return single space
*/
private String sp() {
return pretty? " ": "";
}
/**
* Gets message broker
* @return the messageBroker
*/
public MessageBroker getMessageBroker() {
return messageBroker;
}
/**
* Sets message broker
* @param messageBroker the messageBroker to set
*/
public void setMessageBroker(MessageBroker messageBroker) {
this.messageBroker = messageBroker;
}
}