/**
* Copyright 2014 Comcast Cable Communications Management, LLC
*
* This file is part of CATS.
*
* CATS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CATS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CATS. If not, see <http://www.gnu.org/licenses/>.
*/
package com.comcast.cats.service.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml;
import com.comcast.cats.info.VideoRecorderResponse;
import com.comcast.cats.info.VideoRecorderServiceConstants;
import com.comcast.cats.recorder.domain.Recording;
/**
* A simple REST client API based on Apache HttpClient/SnakeYAML.
*
* @author ssugun00c
*
*/
public class HttpClientUtil
{
/**
* log4j logger instance of this class.
*/
private static Logger logger = LoggerFactory.getLogger( HttpClientUtil.class );
/**
* Singleton enforcer.
*/
private HttpClientUtil()
{
}
public static synchronized Object getForObject( String uri, Map< String, String > paramMap )
{
Object responseObject = new Object();
HttpMethod httpMethod = new GetMethod( uri );
if ( ( null != paramMap ) && ( !paramMap.isEmpty() ) )
{
httpMethod.setQueryString( getNameValuePair( paramMap ) );
}
Yaml yaml = new Yaml();
HttpClient client = new HttpClient();
InputStream responseStream = null;
Reader inputStreamReader = null;
try
{
int responseCode = client.executeMethod( httpMethod );
if ( HttpStatus.SC_OK != responseCode )
{
logger.error( "[ REQUEST ] " + httpMethod.getURI().toString() );
logger.error( "[ METHOD ] " + httpMethod.getName() );
logger.error( "[ STATUS ] " + responseCode );
}
else
{
logger.trace( "[ REQUEST ] " + httpMethod.getURI().toString() );
logger.trace( "[ METHOD ] " + httpMethod.getName() );
logger.trace( "[ STATUS ] " + responseCode );
}
responseStream = httpMethod.getResponseBodyAsStream();
inputStreamReader = new InputStreamReader( responseStream, VideoRecorderServiceConstants.UTF );
responseObject = yaml.load( inputStreamReader );
}
catch ( IOException ioException )
{
ioException.printStackTrace();
}
finally
{
cleanUp( inputStreamReader, responseStream, httpMethod );
}
return responseObject;
}
public static synchronized Object postForObject( String uri, Map< String, String > paramMap )
{
Object responseObject = new Object();
HttpMethod httpMethod = new PostMethod( uri );
if ( ( null != paramMap ) && ( !paramMap.isEmpty() ) )
{
httpMethod.setQueryString( getNameValuePair( paramMap ) );
}
Yaml yaml = new Yaml();
HttpClient client = new HttpClient();
InputStream responseStream = null;
Reader inputStreamReader = null;
try
{
int responseCode = client.executeMethod( httpMethod );
if ( HttpStatus.SC_OK != responseCode )
{
logger.error( "[ REQUEST ] " + httpMethod.getURI().toString() );
logger.error( "[ METHOD ] " + httpMethod.getName() );
logger.error( "[ STATUS ] " + responseCode );
}
else
{
logger.trace( "[ REQUEST ] " + httpMethod.getURI().toString() );
logger.trace( "[ METHOD ] " + httpMethod.getName() );
logger.trace( "[ STATUS ] " + responseCode );
}
responseStream = httpMethod.getResponseBodyAsStream();
inputStreamReader = new InputStreamReader( responseStream, VideoRecorderServiceConstants.UTF );
responseObject = yaml.load( inputStreamReader );
}
catch ( IOException ioException )
{
ioException.printStackTrace();
}
finally
{
cleanUp( inputStreamReader, responseStream, httpMethod );
}
return responseObject;
}
public static synchronized Object deleteForObject( String uri, Map< String, String > paramMap )
{
Object responseObject = new Object();
HttpMethod httpMethod = new DeleteMethod( uri );
if ( ( null != paramMap ) && ( !paramMap.isEmpty() ) )
{
httpMethod.setQueryString( getNameValuePair( paramMap ) );
}
Yaml yaml = new Yaml();
HttpClient client = new HttpClient();
InputStream responseStream = null;
Reader inputStreamReader = null;
try
{
int responseCode = client.executeMethod( httpMethod );
if ( HttpStatus.SC_OK != responseCode )
{
logger.error( "[ REQUEST ] " + httpMethod.getURI().toString() );
logger.error( "[ METHOD ] " + httpMethod.getName() );
logger.error( "[ STATUS ] " + responseCode );
}
else
{
logger.trace( "[ REQUEST ] " + httpMethod.getURI().toString() );
logger.trace( "[ METHOD ] " + httpMethod.getName() );
logger.trace( "[ STATUS ] " + responseCode );
}
responseStream = httpMethod.getResponseBodyAsStream();
inputStreamReader = new InputStreamReader( responseStream, VideoRecorderServiceConstants.UTF );
responseObject = yaml.load( inputStreamReader );
}
catch ( IOException ioException )
{
ioException.printStackTrace();
}
finally
{
cleanUp( inputStreamReader, responseStream, httpMethod );
}
return responseObject;
}
public static synchronized Object postForObject( String requestUrl, byte[] payload )
{
Object responseObject = new Object();
PostMethod httpMethod = new PostMethod( requestUrl );
InputStream responseStream = null;
Reader inputStreamReader = null;
httpMethod.addRequestHeader( VideoRecorderServiceConstants.CONTENT_TYPE,
VideoRecorderServiceConstants.APPLICATION_XML );
RequestEntity requestEntity = new ByteArrayRequestEntity( payload, VideoRecorderServiceConstants.UTF );
httpMethod.setRequestEntity( requestEntity );
try
{
int responseCode = new HttpClient().executeMethod( httpMethod );
if ( HttpStatus.SC_OK != responseCode )
{
logger.error( "[ REQUEST ] " + httpMethod.getURI().toString() );
logger.error( "[ METHOD ] " + httpMethod.getName() );
logger.error( "[ STATUS ] " + responseCode );
}
else
{
logger.trace( "[ REQUEST ] " + httpMethod.getURI().toString() );
logger.trace( "[ METHOD ] " + httpMethod.getName() );
logger.trace( "[ STATUS ] " + responseCode );
}
responseStream = httpMethod.getResponseBodyAsStream();
inputStreamReader = new InputStreamReader( responseStream, VideoRecorderServiceConstants.UTF );
responseObject = new Yaml().load( inputStreamReader );
}
catch ( IOException ioException )
{
ioException.printStackTrace();
}
finally
{
cleanUp( inputStreamReader, responseStream, httpMethod );
}
return responseObject;
}
public static synchronized byte[] getPayload( Object domain, boolean prettyPrint )
{
byte[] payload = null;
String xml = null;
StringWriter writer = new StringWriter();
try
{
JAXBContext context = JAXBContext.newInstance( domain.getClass() );
Marshaller marshaller = context.createMarshaller();
if ( prettyPrint )
{
marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
}
marshaller.marshal( domain, writer );
xml = writer.toString();
}
catch ( JAXBException e )
{
logger.error( "[ JAXBException ] " + e.getMessage() );
}
logger.trace( "[ PAYLOAD ] " + xml );
if ( null != xml )
{
payload = xml.getBytes();
}
return payload;
}
public static synchronized VideoRecorderResponse stopRecordingByRecordingId( int recordingId )
{
VideoRecorderResponse videoRecorderResponse = ( VideoRecorderResponse ) postForObject(
getRequestUri( VideoRecorderServiceConstants.REST_REQUEST_STOP ),
getParamMapByRecordingId( recordingId ) );
return videoRecorderResponse;
}
public static synchronized VideoRecorderResponse startRecording( Recording recording )
{
VideoRecorderResponse videoRecorderResponse = ( VideoRecorderResponse ) postForObject(
getRequestUri( VideoRecorderServiceConstants.REST_REQUEST_SUBMIT ), getPayload( recording, true ) );
return videoRecorderResponse;
}
public static synchronized VideoRecorderResponse getStatusByRecordingId( int recordingId )
{
VideoRecorderResponse videoRecorderResponse = ( VideoRecorderResponse ) getForObject(
getRequestUri( VideoRecorderServiceConstants.REST_REQUEST_STATUS ),
getParamMapByRecordingId( recordingId ) );
return videoRecorderResponse;
}
/**
* A generic method to create NameValuePair from Map.
*
* @param paramMap
* @return
*/
private static synchronized NameValuePair[] getNameValuePair( Map< String, String > paramMap )
{
List< NameValuePair > parametersList = new ArrayList< NameValuePair >();
for ( Map.Entry< String, String > entry : paramMap.entrySet() )
{
String key = entry.getKey();
String value = entry.getValue();
if ( ( null != key ) && ( null != value ) && ( !key.isEmpty() ) && ( !value.isEmpty() ) )
{
NameValuePair nameValuePair = new NameValuePair( key, value );
parametersList.add( nameValuePair );
}
}
NameValuePair[] parameters = parametersList.toArray( new NameValuePair[ parametersList.size() ] );
return parameters;
}
private static synchronized String getRequestUri( String restRequest )
{
String requestUri = System
.getProperty( VideoRecorderServiceConstants.SYSTEM_PROPERTY_CATS_PVR_REST_API_BASE_URL )
+ VideoRecorderServiceConstants.REST_REQUEST_INTERNAL_BASE_PATH + restRequest;
return requestUri;
}
private static synchronized Map< String, String > getParamMapByRecordingId( int recordingId )
{
Map< String, String > paramMap = new HashMap< String, String >();
paramMap.put( VideoRecorderServiceConstants.REST_QUERY_PARAM_RECORDING_ID, String.valueOf( recordingId ) );
return paramMap;
}
/**
* Helper method to clean up resources. This is important as the number of
* open files/streams are limited in an operating system.
*
* @param bufferedReader
* @param inputStreamReader
* @param responseStream
* @param httpMethod
* @param client
*/
private static synchronized void cleanUp( Reader inputStreamReader, InputStream responseStream,
HttpMethod httpMethod )
{
if ( inputStreamReader != null )
{
try
{
inputStreamReader.close();
}
catch ( IOException e )
{
logger.warn( "Exception caught trying to close inputStreamReader", e );
}
}
if ( responseStream != null )
{
try
{
responseStream.close();
}
catch ( IOException e )
{
logger.warn( "Exception caught trying to close responseStream", e );
}
}
if ( httpMethod != null )
{
httpMethod.releaseConnection();
}
}
}