/*
* 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.
*/
package org.apache.sling.pipes.internal;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.Iterator;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.JSONObject;
import org.apache.sling.commons.json.JSONTokener;
import org.apache.sling.pipes.BasePipe;
import org.apache.sling.pipes.Plumber;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Pipe outputting binding related to a json stream: either an object
*/
public class JsonPipe extends BasePipe {
private static Logger logger = LoggerFactory.getLogger(JsonPipe.class);
public static final String RESOURCE_TYPE = "slingPipes/json";
HttpClient client;
JSONArray array;
Object binding;
int index = -1;
public final String REMOTE_START = "http";
public JsonPipe(Plumber plumber, Resource resource) throws Exception {
super(plumber, resource);
configureHttpClient();
}
/**
* Configure http client
*/
private void configureHttpClient(){
HttpConnectionManager manager = new MultiThreadedHttpConnectionManager();
HttpConnectionManagerParams params = new HttpConnectionManagerParams();
manager.setParams(params);
client = new HttpClient(manager);
client.getParams().setAuthenticationPreemptive(false);
}
@Override
public Object getOutputBinding() {
return binding;
}
/**
* Retrieve remote / expression JSON String, or null if any problem occurs
* @return JSON serialization of the result
*/
private String retrieveJSONString() {
String json = null;
String expression = getExpr();
if (expression.startsWith(REMOTE_START)){
GetMethod method = null;
HttpState httpState = new HttpState();
InputStream responseInputStream = null;
try {
String url = getExpr();
if (StringUtils.isNotBlank(url)) {
method = new GetMethod(url);
logger.debug("Executing GET {}", url);
int status = client.executeMethod(null, method, httpState);
if (status == HttpStatus.SC_OK) {
logger.debug("200 received, streaming content");
responseInputStream = method.getResponseBodyAsStream();
StringWriter writer = new StringWriter();
IOUtils.copy(responseInputStream, writer, "utf-8");
json = writer.toString();
}
}
}
catch(Exception e){
logger.error("unable to retrieve the data", e);
}finally{
if (method != null) {
method.releaseConnection();
}
IOUtils.closeQuietly(responseInputStream);
}
} else {
//other try: given expression *is* json
json = expression;
}
return json;
}
/**
* in case there is no successful retrieval of some JSON data, we cut the pipe here
* @return input resource of the pipe, can be reouputed N times in case output json binding is an array of
* N element (output binding would be here each time the Nth element of the array)
*/
public Iterator<Resource> getOutput() {
Iterator<Resource> output = EMPTY_ITERATOR;
binding = null;
String jsonString = retrieveJSONString();
if (StringUtils.isNotBlank(jsonString)){
try {
JSONTokener tokener = new JSONTokener(jsonString);
char firstChar = tokener.next();
if (firstChar == '[') {
binding = array = new JSONArray(jsonString);
index = 0;
output = new Iterator<Resource>() {
@Override
public boolean hasNext() {
return index < array.length();
}
@Override
public Resource next() {
try {
binding = array.get(index);
} catch(Exception e){
logger.error("Unable to retrieve {}nth item of jsonarray", index, e);
}
index++;
return getInput();
}
};
} else if (firstChar == '{') {
binding = new JSONObject(jsonString);
output = super.getOutput();
} else {
//simple string
binding = jsonString;
output = super.getOutput();
}
} catch (JSONException e) {
logger.error("unable to parse JSON {} ", jsonString, e);
}
}
return output;
}
}