/** * 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; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; import javax.annotation.PostConstruct; import javax.enterprise.event.Event; import javax.faces.application.FacesMessage; import javax.faces.bean.ManagedBean; import javax.faces.bean.SessionScoped; import javax.faces.component.UIComponent; import javax.faces.component.html.HtmlSelectOneMenu; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.faces.convert.Converter; import javax.faces.event.ValueChangeEvent; import javax.faces.validator.ValidatorException; import javax.inject.Inject; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.jboss.resteasy.client.ProxyFactory; import org.primefaces.event.RowEditEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.comcast.cats.config.ui.recording.SettopRecordingService; import com.comcast.cats.domain.SettopDesc; import com.comcast.cats.domain.SettopReservationDesc; import com.comcast.cats.keymanager.domain.Remote; import com.comcast.cats.local.domain.Rack; import com.comcast.cats.local.domain.SettopType; import com.comcast.cats.local.domain.Slot; import com.comcast.cats.local.domain.TraceType; import com.comcast.cats.service.KeyManagerConstants; import com.comcast.cats.service.KeyManagerProxy; @ManagedBean @SessionScoped public class SettopController implements Converter { public static final String TRACE_TYPE_KEY = "Trace_Type"; private static final String MAC_ID_REGEX = "^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$"; private List< Slot > listableSlots = new ArrayList< Slot >(); private SlotConnectionBean[] selectedSlotConnections; private SlotConnectionBean selectedSlotConnection; Rack selectedRack; HtmlSelectOneMenu slotSelectOneMenu; HtmlSelectOneMenu rackSelectOneMenu; List<SlotConnectionBean> allConnectedSlots; boolean deleteRecordings = false; @Inject SettopSlotConfigService settopSlotConfigService; @Inject RackService rackService; private static KeyManagerProxy keyManager = null; static Logger logger = LoggerFactory.getLogger( SettopController.class ); @Inject SettopRecordingService settopRecordingService; @Inject Event< SettopCreateEvent > settopCreatedNotifier; @Inject Event< SettopEditEvent > settopEditedNotifier; @Inject Event< SettopDeleteEvent > settopDeletedNotifier; static{ if(keyManager == null){ String hostname = System.getProperty( KeyManagerConstants.KEY_MANAGER_PROXY_IP_NAME ); try{ if(hostname == null || hostname.isEmpty()){ hostname = AuthController.getHostAddress(); } logger.info( "KeyManagerProxyProviderRest get() "+hostname ); if(hostname != null){ keyManager = ProxyFactory.create(KeyManagerProxy.class, "http://"+hostname+"/keymanager-service"+KeyManagerConstants.APPLICATION_PATH+KeyManagerConstants.KEYMANAGER_PATH+"/"); }else{ logger.warn( "System property "+KeyManagerConstants.KEY_MANAGER_PROXY_IP_NAME+" may not be set properly" ); } logger.info( "KeyManagerProxyProviderRest keyManagerProxy "+keyManager ); }catch(Exception e){ logger.warn( e.getMessage() ); } } } public SettopController() { } @PostConstruct public void init(){ allConnectedSlots = settopSlotConfigService.getAllConnectedSlots(); } public List< SlotConnectionBean > getAllConnectedSlots() { return allConnectedSlots; } public List< Slot > getListableSlots() { return listableSlots; } public void setListableSlots( List< Slot > listableSlots ) { this.listableSlots = listableSlots; } public void rowEdited( RowEditEvent evt ) { if ( evt.getObject() instanceof SlotConnectionBean ) { SlotConnectionBean editedSlotConnection = ( SlotConnectionBean ) evt.getObject(); if ( editedSlotConnection.getSlot() == null ) { editedSlotConnection.setRack( null ); } saveSlotConnection( editedSlotConnection ); settopEditedNotifier.fire( new SettopEditEvent(editedSlotConnection.getSettop() ) ); //clear the form after successfully saving. editedSlotConnection.setSettop( null ); editedSlotConnection.setRack( null ); editedSlotConnection.setSlot( null ); } } public void onCancel( RowEditEvent evt ){ if ( evt.getObject() instanceof SlotConnectionBean ) { SlotConnectionBean editedSlotConnection = ( SlotConnectionBean ) evt.getObject(); settopSlotConfigService.refresh(); editedSlotConnection = settopSlotConfigService.getSlotConnection( editedSlotConnection.getSettop().getId() ); } } public String saveSlotConnection( SlotConnectionBean slotConnection, SettopDesc settop ) { if ( settop.getId() == null ) { settop.setId( UUID.randomUUID().toString() ); } slotConnection.setSettop( settop ); saveSlotConnection( slotConnection ); clearFormValues( settop ); settop = null; settopCreatedNotifier.fire( new SettopCreateEvent( settop ) ); // POST-Redirect-GET pattern // http://balusc.blogspot.com/2007/03/post-redirect-get-pattern.html return "/settop/List.xhtml?faces-redirect=true"; } private void clearFormValues( SettopDesc settop ) { settop.setName( null ); settop.setHostMacAddress( null ); settop.setModel( null ); settop.setManufacturer( null ); settop.setUnitAddress( null ); settop.setMcardMacAddress( null ); settop.setMCardSerialNumber( null ); settop.setContent( null ); settop.setRemoteType( null ); settop.setHostIp4Address( null ); settop.setId( null ); settop.setExtraProperties( null ); settop.setSerialNumber( null ); } public void saveSlotConnection( SlotConnectionBean slotConnection ) { if ( slotConnection.getSettop().getId() == null ) { slotConnection.getSettop().setId( UUID.randomUUID().toString() ); } settopSlotConfigService.saveSlotConnection( slotConnection ); refresh(); FacesContext context = FacesContext.getCurrentInstance(); FacesMessage msg = new FacesMessage(); if ( context != null ) { msg.setSummary( "Settop " + slotConnection.getSettop().getName() + " saved successfully" ); msg.setSeverity( FacesMessage.SEVERITY_INFO ); context.addMessage( "response", msg ); logger.trace( "slotConnection saved " + slotConnection ); } } public synchronized void deleteSettopAndSlotConnection() { if(selectedSlotConnection != null){ settopRecordingService.stopRecording( selectedSlotConnection.getSlot(), selectedSlotConnection.getSettop().getHostMacAddress() ); settopSlotConfigService.deleteSettopAndConnection( selectedSlotConnection); settopDeletedNotifier.fire( new SettopDeleteEvent( selectedSlotConnection.getSettop() ) ); if(deleteRecordings){ Thread delThread = new Thread(new DeleteRecordingsJob(selectedSlotConnection.getSettop().getHostMacAddress())); delThread.start(); } } refresh(); deleteRecordings = false; } public SlotConnectionBean[] getSelectedSlotConnections() { return selectedSlotConnections; } public void setSelectedSlotConnections( SlotConnectionBean[] selectedSlotConnections ) { this.selectedSlotConnections = selectedSlotConnections; } public void setSelectedSlotConnection ( SlotConnectionBean selectedSlotConnection ) { this.selectedSlotConnection = selectedSlotConnection; } public void clearSlotConnectionSelection ( ) { this.selectedSlotConnection = null; } /** * Converter for slot for selectOneMenu */ @Override public Object getAsObject( FacesContext context, UIComponent comp, String value ) { Slot slot = null; if ( !value.isEmpty() ) { String rackName = value.substring( 0, value.indexOf( "--" ) ).trim(); String slotNumber = value.substring( value.indexOf( "--" ) + 2 ).trim(); slot = rackService.findSlotByRack( rackName, Integer.parseInt( slotNumber ) ); } logger.trace( "value " + value + " Slot " + slot ); return slot; } /** * Converter for slot for selectOneMenu */ @Override public String getAsString( FacesContext context, UIComponent comp, Object object ) { String retVal = ""; if ( object instanceof Slot ) { Slot slot = ( Slot ) object; retVal = slot.getRack().getName() + " -- " + slot.getNumber().toString(); logger.trace( "Slot " + slot + " value " + retVal ); } return retVal; } /** * Validator for mac address name. * * @param context * @param component * @param value * @throws ValidatorException */ public void validateMacAddress( FacesContext context, UIComponent component, Object value ) throws ValidatorException { String macAddress = ( String ) value; if ( selectedSlotConnection == null || !macAddress.equals( selectedSlotConnection.getSettop().getHostMacAddress() ) ) { if(!macAddress.isEmpty()){ if ( !macAddress.matches( MAC_ID_REGEX ) || settopSlotConfigService.isMacAlreadyUsed( macAddress ) ) { logger.debug( "macAddress not valid " + macAddress + " : is already available?? :" + settopSlotConfigService.isMacAlreadyUsed( macAddress ) ); throw new ValidatorException( new FacesMessage( FacesMessage.SEVERITY_ERROR, null, "Not valid" ) ); } } } } /** * Validator for settop name. * * @param context * @param component * @param value * @throws ValidatorException */ public void validateName( FacesContext context, UIComponent component, Object value ) throws ValidatorException { String name = ( String ) value; if ( selectedSlotConnection == null || !name.equals( selectedSlotConnection.getSettop().getName() ) ) { if ( name.isEmpty() || settopSlotConfigService.isSettopNameAlreadyUsed( name ) ) { logger.debug( "Name not valid " + name + " : is already available?? :" + settopSlotConfigService.isSettopNameAlreadyUsed( name ) ); throw new ValidatorException( new FacesMessage( FacesMessage.SEVERITY_ERROR, null, "Not valid" ) ); } } } public List< String > getAvailableRemoteTypes() throws ValidatorException { List< String > remotesTypes = new ArrayList< String >(); if ( keyManager != null ) { try{ List< Remote > remotes = keyManager.remotes(); for ( Remote remote : remotes ) { remotesTypes.add( remote.getName() ); } }catch(Exception e){ logger.warn( "Could not retrieve remote types "+e.getMessage() ); } } return remotesTypes; } public void launchCATSVision( SettopDesc settop ) { FacesContext ctx = null; try { 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 { String macAddress = ""; if ( settop != null && settop.getHostMacAddress() != null ) { macAddress = settop.getHostMacAddress(); } response.setHeader( "Content-Disposition", "attachment; filename=CATSVision_" + macAddress + ".jnlp" ); response.setContentType( "application/x-java-jnlp-file; charset=UTF-8" ); try { logger.debug( "Download CATSVision jnlp template from " + request.getServerName() ); String jnlpText = readURL( "http://" + request.getServerName() + "/webstart/catsvision.template" ); jnlpText = jnlpText.replaceAll( "<host>", request.getServerName() ); jnlpText = jnlpText.replaceAll( "<mac>", macAddress ); out = new DataOutputStream( response.getOutputStream() ); out.writeBytes( jnlpText ); } catch ( Exception e ) { logger.debug( e.getMessage() ); e.printStackTrace(); } finally { if ( out != null ) { out.flush(); out.close(); } } } ctx.responseComplete(); } catch ( Exception e ) { logger.debug( e.getMessage() ); e.printStackTrace(); } } private String readURL( String urlString ) { URL url; InputStream is = null; InputStreamReader isr = null; BufferedReader r = null; StringBuilder str = new StringBuilder(); try { url = new URL( urlString ); is = url.openStream(); isr = new InputStreamReader( is ); r = new BufferedReader( isr ); String tempString = ""; do { tempString = r.readLine(); if ( tempString != null ) { str.append( tempString + "\n" ); } } while ( tempString != null ); } catch ( MalformedURLException e ) { logger.debug( e.getMessage() ); } catch ( IOException e ) { logger.debug( e.getMessage() ); } finally{ if(r != null){ try { r.close(); } catch ( IOException e ) { logger.error( "Could not close BufferedReader "+e.getMessage() ); } } } return str.toString(); } public void handleRackSelect( ValueChangeEvent event ) { setListableSlots( settopSlotConfigService.getAllEmptySlots( ( Rack ) event.getNewValue() ) ); } public void handleSlotSelect( ValueChangeEvent event ) { Slot selectedSlot = ( Slot ) event.getNewValue(); if ( selectedSlot != null ) { List< Slot > emptySlots = settopSlotConfigService.getAllEmptySlots( selectedSlot.getRack() ); if ( !emptySlots.contains( selectedSlot ) ) { // http://balusc.blogspot.com/2012/03/reset-non-processed-input-components-on.html // (Not the solution, but the problem.) rackSelectOneMenu.resetValue(); slotSelectOneMenu.resetValue(); FacesContext context = FacesContext.getCurrentInstance(); if ( context != null ) { logger.debug( "Slot already in use" + selectedSlot ); context.addMessage( null, new FacesMessage( FacesMessage.SEVERITY_ERROR, "Slot already in use", null ) ); context.renderResponse(); } } } } public List< String > getTraceTypes() { List< String > traceTypes = new ArrayList< String >(); for ( TraceType traceType : TraceType.values() ) { traceTypes.add( traceType.getRepresentation() ); } return traceTypes; } public List< String > getSettopTypes() { List< String > settopTypes = new ArrayList< String >(); List< SettopType > types = settopSlotConfigService.getAllSettopTypes(); for ( SettopType settopType : types ) { settopTypes.add( settopType.getName() ); } return settopTypes; } public boolean isDeleteRecordings() { return deleteRecordings; } public void setDeleteRecordings( boolean deleteRecordings ) { this.deleteRecordings = deleteRecordings; } public void autoPopulate( SettopDesc settop ) { SettopType settopType = settopSlotConfigService.getSettopTypeByName( settop.getComponentType() ); if ( settopType != null ) { settop.setManufacturer( settopType.getManufacturer() ); settop.setModel( settopType.getModel() ); settop.setRemoteType( settopType.getRemoteType() ); Map< String, String > properties = settop.getExtraProperties(); properties.put( TRACE_TYPE_KEY, settopType.getTraceType() ); } else { settop.setManufacturer( null ); settop.setModel( null ); settop.setRemoteType( null ); Map< String, String > properties = settop.getExtraProperties(); properties.put( TRACE_TYPE_KEY, null ); } } public String getTraceTypeKey() { return TRACE_TYPE_KEY; } public void refresh() { settopSlotConfigService.refresh(); allConnectedSlots = settopSlotConfigService.getAllConnectedSlots(); } public HtmlSelectOneMenu getSlotSelectOneMenu() { return slotSelectOneMenu; } public void setSlotSelectOneMenu( HtmlSelectOneMenu slotSelectOneMenu ) { this.slotSelectOneMenu = slotSelectOneMenu; } public HtmlSelectOneMenu getRackSelectOneMenu() { return rackSelectOneMenu; } public void setRackSelectOneMenu( HtmlSelectOneMenu rackSelectOneMenu ) { this.rackSelectOneMenu = rackSelectOneMenu; } private class DeleteRecordingsJob implements Runnable{ String macID = ""; public DeleteRecordingsJob(String macID){ this.macID = macID; } @Override public void run() { settopRecordingService.deleteAllRecordingsForSettop( macID ); } } public List< SettopReservationDesc > getAllSettopsByRack(String rackName) { return settopSlotConfigService.getAllSettopsByRack( rackName ); } public void copySelectedSettop(SlotConnectionBean toCopySlotConnection){ if(toCopySlotConnection != null){ SettopReservationDesc toCopySettop = (SettopReservationDesc)toCopySlotConnection.getSettop(); if(toCopySettop != null){ SettopReservationDesc copiedSettop = new SettopReservationDesc(toCopySettop); SlotConnectionBean slotConnection = new SlotConnectionBean(); copiedSettop.setId( null ); copiedSettop.setHostMacAddress( null ); copiedSettop.setMcardMacAddress( null ); copiedSettop.setHostIp4Address( null ); copiedSettop.setName( "Copy of "+copiedSettop.getName() ); slotConnection.setSettop( copiedSettop ); saveSlotConnection( slotConnection ); settopCreatedNotifier.fire( new SettopCreateEvent( copiedSettop ) ); refresh(); } } } }