/**
* 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.config.ui.recording;
import java.io.BufferedInputStream;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.annotation.PostConstruct;
import javax.enterprise.event.Observes;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.primefaces.event.CloseEvent;
import org.primefaces.event.UnselectEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.comcast.cats.config.ui.AuthController;
import com.comcast.cats.config.ui.SettopCreateEvent;
import com.comcast.cats.config.ui.SettopDeleteEvent;
import com.comcast.cats.config.ui.SettopEditEvent;
import com.comcast.cats.config.ui.SettopSlotConfigService;
import com.comcast.cats.config.ui.SlotConnectionBean;
import com.comcast.cats.info.VideoRecorderResponse;
import com.comcast.cats.info.VideoRecorderState;
import com.comcast.cats.local.domain.Slot;
import com.comcast.cats.recorder.domain.Recording;
import com.comcast.cats.recorder.domain.RecordingStatus;
import com.comcast.cats.service.WebServiceReturnEnum;
/**
* Controller for recordings list view.
*
* @author skurup00c
*
*/
@ManagedBean
@SessionScoped
public class SettopRecordingController
{
@Inject
SettopSlotConfigService settopService;
@Inject
SettopRecordingService settopRecordingService;
private SettopRecordingBean[] selectedRecordings;
private SettopRecordingBean selectedRecording;
private List< SettopRecordingBean > recordings = new ArrayList< SettopRecordingBean >();
private MediaInfoBean mediaToPlay;
private String aliasName;
private static String masterRecordDirectory = null;
public static String relativeFilePathForRecording = "";
private static final String RECORDING_PROPERTIES_FILE = "recorder.properties";
private static Logger logger = LoggerFactory.getLogger( SettopRecordingController.class );
private static final String PVR_HTTP_SERVER_BASE_PATH = "pvr.http.server.base.path";
private static final RecordingStatus UNKNOWN_STATUS;
private SettopRecordingBean selectedRecordingHistory;
private SettopRecordingBean[] selectedRecordingHistoryList ;
static
{
Properties prop = new Properties();
try
{
prop.load( SettopRecordingController.class.getClassLoader().getResourceAsStream( RECORDING_PROPERTIES_FILE ) );
relativeFilePathForRecording = ( String ) prop.get( PVR_HTTP_SERVER_BASE_PATH );
logger.info( "relativeFilePathForRecording " + relativeFilePathForRecording );
// check if masterDirectory has been explicitly set already
if ( masterRecordDirectory == null && AuthController.getHostAddress() != null )
{
masterRecordDirectory = "http://" + AuthController.getHostAddress() + relativeFilePathForRecording;
}
}
catch ( FileNotFoundException e )
{
logger.error( "Properties file not found or could not be loaded " + e.getMessage() );
}
catch ( IOException e )
{
logger.error( "Properties file not found or could not be loaded " + e.getMessage() );
}
catch ( Exception e )
{
logger.error( "Properties file not found or could not be loaded " + e.getMessage() );
}
UNKNOWN_STATUS = new RecordingStatus();
UNKNOWN_STATUS.setState( VideoRecorderState.UNKNOWN.name() );
}
@PostConstruct
public void getRecordings(){
refreshRecordingsListing();
}
public synchronized List< SettopRecordingBean > getSettopRecordingStatusList()
{
return recordings;
}
public void handleSettopEditEvent( @Observes SettopEditEvent settopEditEvent )
{
refreshRecordingsListing(); // refresh on view should see updated changes.
}
public void handleSettopCreatedEvent( @Observes SettopCreateEvent settopCreatedEvent )
{
refreshRecordingsListing(); // refresh on view should see updated changes.
}
public void handleSettopDeletedEvent( @Observes SettopDeleteEvent settopDeletedEvent )
{
refreshRecordingsListing(); // refresh on view should see updated changes.
}
private synchronized void refreshRecordingsListing()
{
logger.trace( "refreshRecordingsListing " );
List< SlotConnectionBean > slotConnections = settopService.getAllConnectedSlots();
List<SettopRecordingBean> recordingsList = new ArrayList< SettopRecordingBean >();
for ( SlotConnectionBean slotConnection : slotConnections )
{
VideoRecorderResponse response = null;
SettopRecordingBean recording = new SettopRecordingBean();
try
{
response = settopRecordingService.getRecordingDetails( slotConnection.getSlot(), slotConnection
.getSettop().getHostMacAddress() );
}
catch ( Exception e )
{
logger.warn( "Refresh recording error happened. Maybe video recorder service is down " + e.getMessage() );
}
if ( response != null && response.getResult() != WebServiceReturnEnum.FAILURE )
{
recording.setStatus( response.getRecording().getRecordingStatus() );
recording.setMediaMetaData( response.getRecording().getMediaInfoEntityList() );
recording.setCreatedTime( response.getRecording().getCreatedTime() );
recording.setName( response.getRecording().getName() );
recording.setId( response.getRecording().getId() );
}
else
{
recording.setStatus( UNKNOWN_STATUS );
}
recording.setSettop( slotConnection.getSettop() );
recording.setSlot( slotConnection.getSlot() );
recordingsList.add( recording );
}
recordings = recordingsList;
}
private List< SettopRecordingBean > convertRecordingHistory( List< Recording > recordinghistory )
{
List< SettopRecordingBean > previousRecordings = new ArrayList< SettopRecordingBean >();
if ( recordinghistory != null )
{
for ( int i = recordinghistory.size()-1; i >=0 ; i-- ) //quick and simple solution to ensure latest recording is at top.
{
Recording historyRecord = recordinghistory.get( i );
SettopRecordingBean pastRecording = new SettopRecordingBean();
pastRecording.setStatus( historyRecord.getRecordingStatus() );
pastRecording.setMediaMetaData( historyRecord.getMediaInfoEntityList() );
pastRecording.setCreatedTime( historyRecord.getCreatedTime() );
pastRecording.setName( historyRecord.getName() );
pastRecording.setId( historyRecord.getId() );
previousRecordings.add( pastRecording );
}
}
return previousRecordings;
}
public SettopRecordingBean[] getSelectedRecordings()
{
return selectedRecordings;
}
public void setSelectedRecordings( SettopRecordingBean[] selectedRecordings )
{
this.selectedRecordings = selectedRecordings;
}
public String start( SettopRecordingBean recording )
{
logger.trace( "Start Recording : " + recording.getSettop() );
Slot slot = recording.getSlot();
VideoRecorderResponse response = null;
try
{
response = settopRecordingService.startRecording( slot, recording.getSettop().getHostMacAddress(),aliasName );
}
catch ( Exception e )
{
logger.warn( "Start recording error happened. Maybe video recorder service is down " + e.getMessage() );
}
handleResponse( response, recording );
setMessage( recording, recording.getSettop().getName(), "Started Recording" );
aliasName=null; //reset view
// POST-Redirect-GET pattern
// http://balusc.blogspot.com/2007/03/post-redirect-get-pattern.html
return "/recording/List.xhtml?faces-redirect=true";
}
private void handleResponse( VideoRecorderResponse response, SettopRecordingBean recording )
{
RecordingStatus status;
status = new RecordingStatus();
status.setState( VideoRecorderState.ERROR.name() );
if ( response == null || response.getResult() == WebServiceReturnEnum.FAILURE )
{
if ( response == null )
{
status.setMessage( "Error. Could not reach server" );
recording.setStatus( status );
}
else
{
status.setMessage( response.getMessage() );
if ( response.getRecording() != null )
{
recording.setStatus( response.getRecording().getRecordingStatus() );
}
else
{
recording.setStatus( status );
}
}
}
else
{
recording.setMediaMetaData( response.getRecording().getMediaInfoEntityList() );
if ( response.getRecording() != null )
{
recording.setStatus( response.getRecording().getRecordingStatus() );
}
else
{
status.setMessage( "Server returned true, but no recording found" );
recording.setStatus( status );
}
}
}
private void setMessage( SettopRecordingBean recording, String settopName, String action )
{
FacesContext context = FacesContext.getCurrentInstance();
if ( recording.getState().equals( VideoRecorderState.ERROR.name() ) )
{
context.addMessage(
null,
new FacesMessage( FacesMessage.SEVERITY_ERROR, "ERROR : " + settopName, recording
.getStatusMessage() ) );
}
else
{
context.addMessage( null, new FacesMessage( FacesMessage.SEVERITY_INFO, "Success : " + action + " : "
+ settopName, recording.getStatusMessage() ) );
}
}
public String stop( SettopRecordingBean recording )
{
logger.trace( "Stop Recording : " + recording.getSettop() );
Slot slot = recording.getSlot();
VideoRecorderResponse response = null;
try
{
response = settopRecordingService.stopRecording( slot, recording.getSettop().getHostMacAddress() );
}
catch ( Exception e )
{
logger.warn( "Start recording error happened. Maybe video recorder service is down " + e.getMessage() );
}
handleResponse( response, recording );
setMessage( recording, recording.getSettop().getName(), "Stopped Recording" );
// POST-Redirect-GET pattern
// http://balusc.blogspot.com/2007/03/post-redirect-get-pattern.html
return "/recording/List.xhtml?faces-redirect=true";
}
public MediaInfoBean getMediaToPlay()
{
return mediaToPlay;
}
public void setMediaToPlay( MediaInfoBean mediaToPlay )
{
this.mediaToPlay = mediaToPlay;
}
public SettopRecordingBean getSelectedRecording()
{
return selectedRecording;
}
public void setSelectedRecording( SettopRecordingBean selectedRecording )
{
this.selectedRecording = selectedRecording;
obtainHistoryList(this.selectedRecording);
}
private void obtainHistoryList(SettopRecordingBean recording )
{
try
{
List< Recording > recordinghistory = settopRecordingService.getRecordingHistory( recording.getSettop()
.getHostMacAddress() );
recording.setRecordingHistoryList( convertRecordingHistory( recordinghistory ) );
}
catch ( Exception e )
{
logger.warn( "Retrieving Recording History error happened. Maybe video recorder service is down "
+ e.getMessage() );
}
}
public String getMasterRecordDirectory()
{
if ( masterRecordDirectory == null )
{
masterRecordDirectory = "http://" + AuthController.getHostAddress() + relativeFilePathForRecording;
}
return masterRecordDirectory;
}
public void setMasterRecordDirectory( String masterRecordDirectory )
{
logger.trace( "setMasterRecordDirectory : " + masterRecordDirectory );
SettopRecordingController.masterRecordDirectory = masterRecordDirectory;
}
public void recordSelectedSettops()
{
logger.trace( "recordSelectedSettops : " + ( selectedRecordings == null ) );
if ( selectedRecordings != null && selectedRecordings.length > 0 )
{
for ( SettopRecordingBean recording : selectedRecordings )
{
start( recording );
}
}
}
public void stopSelectedSettops()
{
logger.trace( "stopSelectedSettops : " + ( selectedRecordings == null ) );
if ( selectedRecordings != null && selectedRecordings.length > 0 )
{
for ( SettopRecordingBean recording : selectedRecordings )
{
stop( recording );
}
}
}
public String getAliasName()
{
return aliasName;
}
public void setAliasName( String aliasName )
{
this.aliasName = aliasName;
}
public void refreshAll()
{
logger.trace( "refreshAll " );
refreshRecordingsListing();
}
public void clearMediaToPlay()
{
setMediaToPlay( null );
}
public void deleteRecording(){
deleteRecording(selectedRecordingHistory);
selectedRecordingHistory = null;
}
public void deleteRecording(SettopRecordingBean recording){
if(recording != null){
VideoRecorderResponse response = null;
try
{
response = settopRecordingService.deleteRecording( recording.getId());
obtainHistoryList(this.selectedRecording);
}
catch ( Exception e )
{
logger.warn( "Delete failed. Maybe video recorder service is down " + e.getMessage() );
}
handleDeleteRespone(response);
}
}
public void deleteMedia(MediaInfoBean media){
VideoRecorderResponse response = null;
try
{
response = settopRecordingService.deleteFile( media.getId());
obtainHistoryList(this.selectedRecording);
this.selectedRecording.getMediaInfo().remove(media); //update media list
System.out.println("Removed media "+selectedRecording.getMediaInfo().size());
}
catch ( Exception e )
{
logger.warn( "Delete failed. Maybe video recorder service is down " + e.getMessage() );
}
handleDeleteRespone(response);
}
private void handleDeleteRespone(VideoRecorderResponse response){
FacesContext context = FacesContext.getCurrentInstance();
if(response != null){
if(WebServiceReturnEnum.FAILURE.equals( response.getResult())){
context.addMessage(
null,
new FacesMessage( FacesMessage.SEVERITY_ERROR, "DELETE ERROR",response.getMessage()) );
}
}else{
context.addMessage(
null,
new FacesMessage( FacesMessage.SEVERITY_ERROR, "No response from server","Maybe service is down" ));
}
}
public void downloadMedia( MediaInfoBean mediaInfoBean )
{
try
{
FacesContext ctx = FacesContext.getCurrentInstance();
ExternalContext ectx = ctx.getExternalContext();
HttpServletRequest request = ( HttpServletRequest ) ectx.getRequest();
HttpServletResponse response = ( HttpServletResponse ) ectx.getResponse();
DataOutputStream out = null;
if ( request.getParameter( "target" ) != null )
{
RequestDispatcher dispatcher = request.getRequestDispatcher( request.getParameter( "target" ) );
dispatcher.forward( request, response );
}
else
{
response.setContentType( "APPLICATION/OCTET-STREAM" );
response.setHeader( "Content-Disposition", "attachment; filename=" + mediaInfoBean.getFileName() );
BufferedInputStream input = null;
try
{
out = new DataOutputStream( response.getOutputStream() );
input = new BufferedInputStream( new URL( mediaInfoBean.getFilePath() ).openStream() );
byte[] buffer = new byte[ 1024 ]; // 1024 buffer size
int length;
while ( ( length = input.read( buffer ) ) > 0 )
{
out.write( buffer, 0, length );
}
}
catch ( Exception e )
{
logger.debug( e.getMessage() );
}
finally
{
if ( out != null )
{
out.flush();
out.close();
}
if(input != null){
input.close();
}
}
}
ctx.responseComplete();
}
catch ( Exception e )
{
logger.debug( e.getMessage() );
e.printStackTrace();
}
}
public SettopRecordingBean getSelectedRecordingHistory()
{
return selectedRecordingHistory;
}
public void setSelectedRecordingHistory( SettopRecordingBean selectedRecordingHistory )
{
this.selectedRecordingHistory = selectedRecordingHistory;
}
public void handleRecordingHistoryDlgClose(CloseEvent event) {
selectedRecordingHistory = null;
selectedRecordingHistoryList = null;
}
public SettopRecordingBean[] getSelectedRecordingHistoryList() {
return selectedRecordingHistoryList;
}
public void setSelectedRecordingHistoryList(
SettopRecordingBean[] selectedRecordingHistoryList) {
if(selectedRecordingHistoryList != null && selectedRecordingHistoryList.length > 0){
selectedRecordingHistory = selectedRecordingHistoryList[0];
}
this.selectedRecordingHistoryList = selectedRecordingHistoryList;
}
public void deleteRecordingsList(){
if(selectedRecordingHistoryList != null && selectedRecordingHistoryList.length > 0){
for(SettopRecordingBean recording : selectedRecordingHistoryList){
deleteRecording(recording);
}
}
selectedRecordingHistoryList = null;
selectedRecordingHistory = null;
}
}