/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * This software is the proprietary information of Sun Microsystems, Inc.
 * Use is subject to license terms.
 *
 * Copyright 2004 Sun Microsystems, Inc.  Tous droits r?serv?s.
 * Ce logiciel est propri?t? de Sun Microsystems, Inc.
 * Distribu? par des licences qui en restreignent l'utilisation.
 *
 * ident        "@(#)STORE_SRVImpl.java 1.25     04/07/28 SMI"
 *
 */

package com.sun.mfwk.examples.storeCP;


// java imports
//

import java.util.*;
import java.io.*;
import java.net.UnknownHostException;
import java.rmi.*;
import java.rmi.server.*;
import java.util.logging.Logger;


// JDMK import
import com.sun.jdmk.comm.*;
import com.sun.jdmk.*;

// JMX RI imports
import javax.management.*;
import javax.management.remote.*;
import javax.management.remote.jmxmp.*;

// JESMA transaction API
import com.sun.mfwk.trans.*;
import com.sun.mfwk.util.instrum.*;
import com.sun.mfwk.discovery.*;
import com.sun.mfwk.util.log.*;

// Security
import com.sun.mfwk.security.factory.*;
import java.security.*;

public class STORE_SRVImpl extends UnicastRemoteObject implements STORE_SRV {
    
    
    private STORE MyStore;
    private MSG_SRV MyLogSrv;
    
    private MBeanServer mbs = null;
    private MfTransactionFactory tranFactory ;
    private MfTransactionDefinition SEARCHTranDef, MODIFYTranDef, REMOVETranDef;
    private MfTransactionMetrics SEARCHServiceMetrics, MODIFYServiceMetrics, REMOVEServiceMetrics;
    private MfResourceMetrics STOREResourceMetrics;
    private MfExternalResourceMetrics MSG_SRVExternalResourceMetrics;
    private MfStatus STORE_SRVStatusMetrics;
    private MfInstrumManagement STORE_SRVImgt;
    private MfInstrumConfig STORE_SRVCfg;
    
    private boolean isDegraded = false;
    private Integer port = new Integer(0);    
    private String instanceId = "1099"; // we use the rmi port to identify the instance

    private static final String USAGE = "java com.sun.mfwk.examples.storeCP.STORE_SRVImpl [-p <port>] [-k <keystore> -f <password file>]";
    
    private Logger logger = null;
    
    private String keystore;
    private String passfile;
    private boolean isSecured = false;
    
    
    /*
     ** Constructor
     */
    public STORE_SRVImpl() throws RemoteException {
        super();
        MyStore = new STORE();
        try {
            MfLogService logSrv = new MfLogService("StoreSrv");
            logger = MfLogService.getLogger("STORE_SRV");
            MyLogSrv = new MSG_SRV();
        } catch (IOException e) {
            logger.info("Log service is not available. We run in DEGRADED state.\n");
            isDegraded = true;
        }
        
    }
    
    private String parseargs(String[] args) {
        int index = 0;
        String port = "";
        String serviceName = "";
        boolean has_k=false;
        boolean has_f=false;
        if (args.length > 6) {
            System.out.println(USAGE);
            System.exit(1);
        }
        while (index < args.length) {
            if (args[index].equals("-p")) {
                if (++index == args.length) {
                    System.err.println("Missing port number\n");
                    System.err.println(USAGE);
                    System.exit(1);
                }
                port = args[index++];
                instanceId = port.toString();
                continue;
            }
            if (args[index].equals("-k")) {
                if (++index == args.length) {
                    System.err.println("Missing keystore filename\n");
                    System.err.println(USAGE);
                    System.exit(1);
                }
                keystore=args[index++];
                has_k=true;
                continue;
            }
            if (args[index].equals("-f")) {
                if (++index == args.length) {
                    System.err.println("Missing password filename\n");
                    System.err.println(USAGE);
                    System.exit(1);
                }
                passfile=args[index++];
                has_f=true;
                continue;
            }
	    // Unknown argument
	    System.out.println("Unknown argument: "+args[index]);
	    System.out.println(USAGE);
            System.exit(1);
        }
        if (has_k && has_f) {
            isSecured=true;
        }
        if ( (has_k && !has_f) || (!has_k && has_f)) {
            System.out.println(USAGE);
            System.exit(1);
        }
        
        if (port.length() == 0) {
            serviceName = "//localhost/STORE_SRV";
        } else {
            serviceName = "//localhost:" + port.toString() + "/STORE_SRV";
        }
        return serviceName;
    }
    
    
    
    public static void main(String[] args) {
        //if (System.getSecurityManager() == null) {
        //             System.setSecurityManager(new RMISecurityManager());
        //}
        
        // We bind our services to the RMI registry.
        // The RMI connection is used for the implementation of the services not for the monitoring
        try {
            STORE_SRVImpl mySTORE_SRV = new STORE_SRVImpl();
            String name = mySTORE_SRV.parseargs(args);
            Naming.rebind(name, mySTORE_SRV);
            // Initialization of monitoring
            mySTORE_SRV.initMonitoring();
        } catch (Exception e) {
            System.err.println("STORE_SRV RMI binding exception: " +
            e.getMessage());
            System.exit(1);
        }
        
    }
    
    
    public String SEARCH(String key) throws RemoteException {
        String result = "";
        
        // Define the MfTransaction instance (start/stop mode)
        MfTransaction tran = tranFactory.newTransaction(SEARCHTranDef, null);
        
        // Start the transaction
        tran.start();
        
        // call MSG_SRV service to log
        log("SEARCH request on key " + key + "\n");
        
        // call STORE
        result = MyStore.SEARCH(key);
        
        // call MSG_SRV service to log
        log("SEARCH request on key " + key + " gives result : " + result + "\n");
        
        if ( result.equals(STORE.ERROR) ) {
            tran.stop(MfConstants.STATUS_FAILED);
        } else if ( result.equals(STORE.NOT_AVAILABLE) ) {
            tran.stop(MfConstants.STATUS_FAILED);
        } else {
            tran.stop(MfConstants.STATUS_GOOD);
        }
        
        return result;
    }
    
    public String MODIFY(String key, String value) throws RemoteException {
        String result = "";
        
        // Define the MfTransaction instance (start/stop mode)
        MfTransaction tran = tranFactory.newTransaction(MODIFYTranDef, null);
        
        // Start the transaction
        tran.start();
        
        // call MSG_SRV service to log
        log("MODIFY request on (key,value) : (" + key + ", " + value + ")");
        
        // call STORE
        result = MyStore.MODIFY(key, value);
        
        // call MSG_SRV service to log
        log("MODIFY request on  (key,value) : (" + key + ", " + value + ") gives result : " + result + "\n");
        
        if ( result.equals(STORE.ERROR) ) {
            tran.stop(MfConstants.STATUS_FAILED);
        } else if ( result.equals(STORE.NOT_AVAILABLE) ) {
            tran.stop(MfConstants.STATUS_GOOD);
        } else {
            tran.stop(MfConstants.STATUS_GOOD);
        }
        
        return result;
    }
    
    public String REMOVE(String key) throws RemoteException {
        
        String result = "";
        
        // Define the MfTransaction instance (start/stop mode)
        MfTransaction tran = tranFactory.newTransaction(REMOVETranDef, null);
        
        // Start the transaction
        tran.start();
        
        // call MSG_SRV service to log
        log("REMOVE request on key " + key + "\n");
        
        // call STORE
        result = MyStore.REMOVE(key);
        
        // call MSG_SRV service to log
        log("REMOVE request on key " + key + " gives result : " + result + "\n");
        
        if ( result.equals(STORE.ERROR) ) {
            tran.stop(MfConstants.STATUS_FAILED);
        } else if ( result.equals(STORE.NOT_AVAILABLE) ) {
            tran.stop(MfConstants.STATUS_FAILED);
        } else {
            tran.stop(MfConstants.STATUS_GOOD);
        }
        
        return result;
    }
    
    
    public void initMonitoring() {
        
        JMXServiceURL addr;
        
        // Parse system properties to check if LEVEL_TRACE and/or
        // LEVEL_DEBUG are set and enable the TRACE level accordingly
        try {
            TraceManager.parseTraceProperties();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        
        /*
         ** Create the MBean server
         */
        mbs = MBeanServerFactory.createMBeanServer();
        
        /*
         ** Create JDMK HTML adaptor for debug
         */
        HtmlAdaptorServer htmlAdaptor = new HtmlAdaptorServer(8083);
        try {
            ObjectName oName =
            new ObjectName("jmx", "type", "htmlAdaptor");
            mbs.registerMBean(htmlAdaptor, oName);
            htmlAdaptor.start();
        } catch(Exception e) {
            e.printStackTrace();
        }
        // waiting to leave starting state...
        while (htmlAdaptor.getState() == CommunicatorServer.STARTING) {
            logger.finest("sleeping on htmlAdaptor");
            sleep(500);
        }
        logger.finest("\nHTML protocol adaptor started on port "+ htmlAdaptor.getPort());
        
        /*
         ** Create JSR 160 JMXMP connector
         */
        JMXConnectorServer cs = null;
        try {
            ObjectName csName = null;
            JMXServiceURL url = new JMXServiceURL("jmxmp", null, 0);
            if (isSecured) {
                // Reading the password from file
                FileReader f = new FileReader(passfile);
                BufferedReader b = new BufferedReader(f);
                String passwd=b.readLine();
                
                // Creating the connector
                cs = MfJMXConnectorServerFactory.newJMXConnectorServer(url, keystore, passwd.toCharArray(), mbs);
                csName = new ObjectName("jmx:type=cserver,name=jmxmpSecuredConnectorServer");
            } else {
                cs = new JMXMPConnectorServer(url, null);
                csName = new ObjectName("jmx:type=cserver,name=jmxmpConnectorServer");
            }
            mbs.registerMBean(cs, csName);
            cs.start();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
 
        logger.finest("\nJMXMP connector started.");
        addr = cs.getAddress();
        logger.finest("# URI is: "+addr);
        
        /*
         ** Instanciate transaction factory
         */
        
        tranFactory = new MfTransactionFactoryImpl();
        
        
        /*
         ** Instanciate the MfStatus Metrics MBean for the STORE_SRV Application
         */
        STORE_SRVStatusMetrics = new MfStatus();
        // Register it in the MBeanServer
        try {
            mbs.registerMBean(STORE_SRVStatusMetrics, MfObjectNameFactory.getStatusName());
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        STORE_SRVStatusMetrics.setOperationalState(MfStatus.OPS_STARTING);
        STORE_SRVStatusMetrics.setOpsStateLastChange(java.lang.System.currentTimeMillis());
        
        /*
         ** Instanciate the MfTransaction Metrics MBean for SEARCH Service
         */
        SEARCHServiceMetrics = new MfTransactionMetrics();
        // Register it in the MBeanServer
        try {
            mbs.registerMBean(SEARCHServiceMetrics, MfObjectNameFactory.getTransactionMetricsName("SEARCH"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        SEARCHServiceMetrics.setOperationalState(MfStatus.OPS_STARTING);
        SEARCHServiceMetrics.setOpsStateLastChange(java.lang.System.currentTimeMillis());
        
        /*
         ** Instanciate the MfTransaction Metrics MBean for MODIFY Service
         */
        MODIFYServiceMetrics = new MfTransactionMetrics();
        // Register it in the MBeanServer
        try {
            mbs.registerMBean(MODIFYServiceMetrics, MfObjectNameFactory.getTransactionMetricsName("MODIFY"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        MODIFYServiceMetrics.setOperationalState(MfStatus.OPS_STARTING);
        MODIFYServiceMetrics.setOpsStateLastChange(java.lang.System.currentTimeMillis());
        
        /*
         ** Instanciate the MfTransaction Metrics MBean for REMOVE Service
         */
        REMOVEServiceMetrics = new MfTransactionMetrics();
        // Register it in the MBeanServer
        try {
            mbs.registerMBean(REMOVEServiceMetrics, MfObjectNameFactory.getTransactionMetricsName("REMOVE"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        REMOVEServiceMetrics.setOperationalState(MfStatus.OPS_STARTING);
        REMOVEServiceMetrics.setOpsStateLastChange(java.lang.System.currentTimeMillis());
        
        /*
         ** Instanciate the Resource Metrics MBean for the STORE Resource
         */
        STOREResourceMetrics = new MfResourceMetrics();
        // Register it in the MBeanServer
        try {
            mbs.registerMBean(STOREResourceMetrics,  MfObjectNameFactory.getResourceMetricsName("STORE"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        STOREResourceMetrics.setOperationalState(MfStatus.OPS_STARTING);
        STOREResourceMetrics.setOpsStateLastChange(java.lang.System.currentTimeMillis());
        
        /*
         ** Set the metrics Mbean on MyStore
         */
        
        MyStore.setResourceMetrics(STOREResourceMetrics);
        
        
        /*
         ** If log service is available then instanciate the External Resource Metrics MBean for the MSG_SRV
         */
        MSG_SRVExternalResourceMetrics = new MfExternalResourceMetrics();
        MSG_SRVExternalResourceMetrics.setProviderUri("localhost://MSG_SRV/log");
        // Register it in the MBeanServer
        try {
            mbs.registerMBean(MSG_SRVExternalResourceMetrics, MfObjectNameFactory.getExternalResourceMetricsName("MSG_SRV"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        MSG_SRVExternalResourceMetrics.setOperationalState(MfStatus.OPS_STARTING);
        MSG_SRVExternalResourceMetrics.setOpsStateLastChange(java.lang.System.currentTimeMillis());
        
        
        /*
         ** If log service is available then set the metrics Mbean on MyLogSrv
         */
        if ( !( MyLogSrv == null ) ) {
            MyLogSrv.setExternalResourceMetrics(MSG_SRVExternalResourceMetrics);
        }
        
        /*
         ** Instanciate the Instrumentation Management MBean for the STORE_SRV
         */
        STORE_SRVImgt = new MfInstrumManagement();
        // Register it in the MBeanServer
        try {
            mbs.registerMBean(STORE_SRVImgt, MfObjectNameFactory.getInstrumManagementName());
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        /*
         ** Instanciate the MfConfig Management MBean for the STORE_SRV and set its attributes
         */
        STORE_SRVCfg = new MfInstrumConfig();
        // Register it in the MBeanServer
        try {
            mbs.registerMBean(STORE_SRVCfg, MfObjectNameFactory.getInstrumConfigName());
            STORE_SRVCfg.setAppRole("standalone server");
            STORE_SRVCfg.setAppURLDescription("STORE_SRV URL Description");
            STORE_SRVCfg.setAppDirectoryDN("STORE_SRV Directory DN");
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        /*
         ** Define the MfTransaction types
         */
        SEARCHTranDef =
        tranFactory.newTransactionDefinition("CP search", "localhost://search", SEARCHServiceMetrics);
        
        MODIFYTranDef =
        tranFactory.newTransactionDefinition("CP modify", "localhost://modify", MODIFYServiceMetrics);
        
        REMOVETranDef =
        tranFactory.newTransactionDefinition("CP remove", "localhost://remove", REMOVEServiceMetrics);
        
        
        /*
         ** Send Discovery multicast
         */
        String userData=null;
        if (isSecured)
            userData="secured";
        else
            userData="unsecured";
        
        try {
            MfDiscoveryResponder testSdk = new MfDiscoveryResponder("STORE_SRV",new String ("instance_" + instanceId),addr.toString(), userData.getBytes());
        } catch (IOException e) {
            logger.info("Unexpected Excpetion while createing Discovery Responder...");
            e.printStackTrace();
        }
        /*
         ** manage operational status and availability status
         */
        SEARCHServiceMetrics.setOperationalState(MfStatus.OPS_RUNNING);
        MODIFYServiceMetrics.setOperationalState(MfStatus.OPS_RUNNING);
        REMOVEServiceMetrics.setOperationalState(MfStatus.OPS_RUNNING);
        STOREResourceMetrics.setOperationalState(MfStatus.OPS_RUNNING);
        STORE_SRVStatusMetrics.setOperationalState(MfStatus.OPS_RUNNING);
        
        SEARCHServiceMetrics.setOpsStateLastChange(java.lang.System.currentTimeMillis());
        MODIFYServiceMetrics.setOpsStateLastChange(java.lang.System.currentTimeMillis());
        REMOVEServiceMetrics.setOpsStateLastChange(java.lang.System.currentTimeMillis());
        STOREResourceMetrics.setOpsStateLastChange(java.lang.System.currentTimeMillis());
        STORE_SRVStatusMetrics.setOpsStateLastChange(java.lang.System.currentTimeMillis());
        
        SEARCHServiceMetrics.setRunningTime(java.lang.System.currentTimeMillis());
        MODIFYServiceMetrics.setRunningTime(java.lang.System.currentTimeMillis());
        REMOVEServiceMetrics.setRunningTime(java.lang.System.currentTimeMillis());
        STOREResourceMetrics.setRunningTime(java.lang.System.currentTimeMillis());
        STORE_SRVStatusMetrics.setRunningTime(java.lang.System.currentTimeMillis());
        
        if (isDegraded) {
            SEARCHServiceMetrics.setAvailabilityState(MfStatus.AVAIL_DEGRADED);
            SEARCHServiceMetrics.setDegradedTime(java.lang.System.currentTimeMillis());
            MODIFYServiceMetrics.setAvailabilityState(MfStatus.AVAIL_DEGRADED);
            MODIFYServiceMetrics.setDegradedTime(java.lang.System.currentTimeMillis());
            REMOVEServiceMetrics.setAvailabilityState(MfStatus.AVAIL_DEGRADED);
            REMOVEServiceMetrics.setDegradedTime(java.lang.System.currentTimeMillis());
            STORE_SRVStatusMetrics.setAvailabilityState(MfStatus.AVAIL_DEGRADED);
            STORE_SRVStatusMetrics.setDegradedTime(java.lang.System.currentTimeMillis());
            MSG_SRVExternalResourceMetrics.setOperationalState(MfStatus.OPS_FAILED);
            MSG_SRVExternalResourceMetrics.setOpsStateLastChange(java.lang.System.currentTimeMillis());
            MSG_SRVExternalResourceMetrics.setAvailabilityState(MfStatus.AVAIL_DEGRADED);
            MSG_SRVExternalResourceMetrics.setDegradedTime(java.lang.System.currentTimeMillis());
            MSG_SRVExternalResourceMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
        } else {
            SEARCHServiceMetrics.setAvailabilityState(MfStatus.AVAIL_NORMAL);
            MODIFYServiceMetrics.setAvailabilityState(MfStatus.AVAIL_NORMAL);
            REMOVEServiceMetrics.setAvailabilityState(MfStatus.AVAIL_NORMAL);
            STORE_SRVStatusMetrics.setAvailabilityState(MfStatus.AVAIL_NORMAL);
            MSG_SRVExternalResourceMetrics.setOperationalState(MfStatus.OPS_RUNNING);
            MSG_SRVExternalResourceMetrics.setOpsStateLastChange(java.lang.System.currentTimeMillis());
            MSG_SRVExternalResourceMetrics.setRunningTime(java.lang.System.currentTimeMillis());
            MSG_SRVExternalResourceMetrics.setAvailabilityState(MfStatus.AVAIL_NORMAL);
            MSG_SRVExternalResourceMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
        }
        STOREResourceMetrics.setAvailabilityState(MfStatus.AVAIL_NORMAL);
        STOREResourceMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
        SEARCHServiceMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
        MODIFYServiceMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
        REMOVEServiceMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
        STORE_SRVStatusMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
        
        
    }
    
    private void log(String msg) {
        if ( ! isDegraded ) {
            try {
                MyLogSrv.log(msg);
            } catch (Exception e) {
                isDegraded = true;
                MSG_SRVExternalResourceMetrics.setOperationalState(MfStatus.OPS_FAILED);
                MSG_SRVExternalResourceMetrics.setOpsStateLastChange(java.lang.System.currentTimeMillis());
                MSG_SRVExternalResourceMetrics.setAvailabilityState(MfStatus.AVAIL_DEGRADED);
                MSG_SRVExternalResourceMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
                MSG_SRVExternalResourceMetrics.setDegradedTime(java.lang.System.currentTimeMillis());
                SEARCHServiceMetrics.setAvailabilityState(MfStatus.AVAIL_DEGRADED);
                SEARCHServiceMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
                SEARCHServiceMetrics.setDegradedTime(java.lang.System.currentTimeMillis());
                MODIFYServiceMetrics.setAvailabilityState(MfStatus.AVAIL_DEGRADED);
                MODIFYServiceMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
                MODIFYServiceMetrics.setDegradedTime(java.lang.System.currentTimeMillis());
                REMOVEServiceMetrics.setAvailabilityState(MfStatus.AVAIL_DEGRADED);
                REMOVEServiceMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
                REMOVEServiceMetrics.setDegradedTime(java.lang.System.currentTimeMillis());
                STORE_SRVStatusMetrics.setAvailabilityState(MfStatus.AVAIL_DEGRADED);
                STORE_SRVStatusMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
                STORE_SRVStatusMetrics.setDegradedTime(java.lang.System.currentTimeMillis());
                // If we canot log using the external Log Service, we print on stdout
                System.out.println("LOG : " + msg);
            }
        } else {
            try {
                MyLogSrv = new MSG_SRV();
                if ( MSG_SRVExternalResourceMetrics == null ) {
                    MSG_SRVExternalResourceMetrics = new MfExternalResourceMetrics();
                    mbs.registerMBean(MSG_SRVExternalResourceMetrics, new ObjectName(MfObjectNameFactory.DOMAIN + ":type=ExternalResource, name=MSG_SRV"));
                }
                MyLogSrv.setExternalResourceMetrics(MSG_SRVExternalResourceMetrics);
                MyLogSrv.log(msg);
                isDegraded = false;
                MSG_SRVExternalResourceMetrics.setOperationalState(MfStatus.OPS_RUNNING);
                MSG_SRVExternalResourceMetrics.setOpsStateLastChange(java.lang.System.currentTimeMillis());
                MSG_SRVExternalResourceMetrics.setRunningTime(java.lang.System.currentTimeMillis());
                MSG_SRVExternalResourceMetrics.setAvailabilityState(MfStatus.AVAIL_NORMAL);
                MSG_SRVExternalResourceMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
                SEARCHServiceMetrics.setAvailabilityState(MfStatus.AVAIL_NORMAL);
                SEARCHServiceMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
                MODIFYServiceMetrics.setAvailabilityState(MfStatus.AVAIL_NORMAL);
                MODIFYServiceMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
                REMOVEServiceMetrics.setAvailabilityState(MfStatus.AVAIL_NORMAL);
                REMOVEServiceMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
                STORE_SRVStatusMetrics.setAvailabilityState(MfStatus.AVAIL_NORMAL);
                STORE_SRVStatusMetrics.setAvailStateLastChange(java.lang.System.currentTimeMillis());
            } catch (Exception e) {
                isDegraded = true;
                // If we canot log using the external Log Service, we print on stdout
                System.out.println("LOG : " + msg);
            }
        }
    }
    
    private static void sleep(long t) {
        try {
            Thread.sleep(t);
        } catch (InterruptedException e) {
            return;
        }
    }
}

