
 //------------------------------------------------------------------------------
 // <copyright file="HpcJava.java" company="Microsoft">
 // 	 Copyright (c) Microsoft Corporation.  All rights reserved.
 // </copyright>
 // <summary>
 //   Java specific functions for Ccp
 // </summary>
 //------------------------------------------------------------------------------
package com.microsoft.hpc.scheduler.session;

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.net.InetAddress;

import javax.xml.bind.JAXBElement;

import com.microsoft.hpc.exceptions.ArgumentException;


/**
 * Java specific functions for Microsoft HPC.
 *
 * Simplifies usage to avoid using <code>ObjectFactory</code> to create <code>JAXBElements</code>, 
 * and to set default username and password for SessionStartInfo and SessionAttachInfo
 * @see ObjectFactory
 * @see JAXBelement
 */
public class HpcJava
{
    static String pass="";
    static String user="";
    
    /**
     * Save the username and password
     * All SessionStartInfos and SessionAttachInfo will be be created with these values as default
     * @param username
     * @param password
     */
    public static void setUsernamePassword(String username, String password)
    {
        user = username;
        pass = password;
    }
    
    /**
     * Filters all messages in err stream from org.springwork and org.apache.cxf
     */
    public static void hideCXF()
    {
        System.setErr(new PrintStream(new cxffilter(System.err)));
    }
    
    /**
     * Creates a request class using the specified objects as input
     * 
     * The order of input should be the order they appear in the <code>TRequest<code> class.
     * The function works by iterating through all <code>set[requestClass]</code> methods and call
     * the corresponding ObjectFactory, if necessary, to create the input.
     * 
     * @param <TRequest> return type
     * @param requestClass  instance to create
     * @param args input objects
     * @return  A request to be sent to the broker using SendRequest
     * @see BrokerClient#sendRequest(Object)
     */
    public static <TRequest> TRequest createRequest(Class<TRequest> requestClass, Object... args)
    {
        return createRequest(requestClass, null, args, false);
    }
    
    /**
     * Creates a request class using the specified objects as input
     * 
     * The order of input should be the order they appear in the <code>TRequest<code> class
     * The function works by iterate through all <code>set[requestClass]</code> methods and call
     * the corresponding ObjectFactory, if necessary, to create the input.
     * 
     * @param <TRequest> return type
     * @param requestClass  instance to create
     * @param classNames class names to check each argument against
     * @param args input objects
     * @return  A request to be sent to the broker using SendRequest
     * @see BrokerClient#sendRequest(Object)
     */
    public static <TRequest> TRequest createRequest(Class<TRequest> requestClass, Class<?> classNames[], Object args[])
    {
        return createRequest(requestClass, classNames, args, true);
    }
    
    /**
     * Creates a request class using the specified objects as input
     * 
     * @param <TRequest> return type
     * @param requestClass  instance to create
     * @param classNames class names to check against
     * @param args input objects
     * @return  A request to be sent to the broker using SendRequest
     * @see BrokerClient#sendRequest(Object)
     */
    private static <TRequest> TRequest createRequest(Class<TRequest> requestClass, Class<?> classNames[], Object args[], boolean checkClassArgs)
    {
        TRequest request;
        try
        {
            if(checkClassArgs && (args.length != classNames.length))
                throw new Exception();
            request = requestClass.newInstance();
            Class<?> ObjectFactory = Class.forName(requestClass.getPackage().getName() + ".ObjectFactory");
            Object of = ObjectFactory.newInstance();
            int i = 0;
            for(Method t : requestClass.getDeclaredMethods())
            {
                if(t.getName().startsWith("set"))
                {
                    String parameter = t.getName().substring("set".length());
                    if(t.getParameterTypes()[0] == JAXBElement.class)
                    {
                        for(Method ob : ObjectFactory.getDeclaredMethods())
                        {
                            String methodName = ob.getName();
                            boolean nameisValid = methodName.startsWith("create" + requestClass.getSimpleName() + parameter) 
                                && !methodName.contains("Response"); 
                                //&& methodName.contains(parameter);
                            
                            if(nameisValid)
                            {
                                if(!checkClassArgs || ob.getParameterTypes()[0] == classNames[i])
                                    t.invoke(request,ob.invoke(of, args[i]));
                                else
                                    throw new Exception();
                            }
                        }
                    }
                    else if(!checkClassArgs || (t.getParameterTypes()[0] == classNames[i]))
                    {
                        t.invoke(request, args[i]);
                    }
                    else
                    {
                        throw new Exception();
                    }
                    i++;
                }
            }
        }
        catch(Exception e)
        {
            throw new ArgumentException("");
        }
        return request;
    }
    
    /**
     * static class defining commonly used Environment variables
     */
    public static class Environment
    {
        static{
            String machineName = null; 
            try
            {
                machineName = InetAddress.getLocalHost().getHostName();
            }
            catch(Exception e)
            {
                ; //do nothing
            }
            finally
            {
                MachineName = machineName;
            }
        }
        public final static String MachineName;
    }
}

/**
 * cxffilter is an extension of <code>FilterOutputStream</code> which filters errstream messages from org.springframework and org.apache.cxf
 *
 */
class cxffilter extends FilterOutputStream
{
    private String[] CXFStatements = new String[] {"org.springframework", "org.apache.cxf"};
    public cxffilter(OutputStream out) 
    {
        super(out);
    }
    
    public void write(byte[] b, int off, int len) throws IOException
    {
        String buf = new String(b);
        for(String test : CXFStatements)
        {
            if(buf.contains(test))
            {
                return;
            }
        }
        out.write(b, off, len);
        
    }
}

