Package de.netsysit.policymanager

Source Code of de.netsysit.policymanager.PolicyUtilities

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package de.netsysit.policymanager;

import de.netsysit.controller.IResultValues;
import de.netsysit.controller.MethodResult;
import de.netsysit.model.ActionModel;
import de.netsysit.model.ActionTupel;
import de.netsysit.policymanager.Enums.*;
import de.netsysit.model.DataBaseModel;
import de.netsysit.model.PolicyModel;
import de.netsysit.model.PolicyReader;
import de.netsysit.model.ReceiverModel;
import de.netsysit.model.XMLPolicyReader;
import java.awt.Component;
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.beans.DefaultPersistenceDelegate;
import java.beans.XMLEncoder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertStore;
import java.security.cert.CertStoreException;
import java.security.cert.CertStoreParameters;
import java.security.cert.CertificateException;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import org.netsys.cms.CMSException;
import org.netsys.cms.CMSProcessable;
import org.netsys.cms.CMSProcessableByteArray;
import org.netsys.cms.CMSSignedData;
import org.netsys.cms.CMSSignedDataGenerator;

/**
* This class contains all the static methods which are used in the program.
* @author ducksoul
*/
public final class PolicyUtilities implements IResultValues {

    private static Locale loc = new Locale("de", "DE");
    private static DataBaseModel dbModel = PolicyManager.getPolicyModel();
    private static ResourceBundle rb;
    private static ResourceBundle mb;
    private static String systemState;
    private static boolean showWarnings = false;
    private static JFileChooser fc = new JFileChooser();

    private PolicyUtilities() {
    }
   
    /**
     * This method shows a SaveFileDialog to choose the filepath to the file
     * in which the database should be saved. The dialog won't be shown if
     * there is alreade a filepath saved in the model.
     * @return A String which contains the filepath of xml database
     */
    public static String showSaveDialog() {
        //fc.addChoosableFileFilter(new DBFileFilter());
        if(dbModel.getFilePath() != null)
            fc.setCurrentDirectory(new File(dbModel.getFilePath()));
       
        if (fc.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
            dbModel.setFilePath(fc.getSelectedFile().getAbsolutePath());
            return fc.getSelectedFile().getAbsolutePath();
        } else {
            return null;
        }
    }

    /**
     * This method sets the static variable loc.
     * @param loc The new Locale
     */
    public static void setLoc(Locale loc) {
        PolicyUtilities.loc = loc;
        rb = ResourceBundle.getBundle("resources.PolicyManager", loc);
        mb = ResourceBundle.getBundle("resources.Messages", loc);
    }

    /**
     * This method returns the current ResourceBundle which contains the
     * Strings of the components in the GUI.
     * @return The actual ResourceBundle of PolicyManager
     */
    public static ResourceBundle getResourceBundle() {
        if (rb == null) {
            rb = ResourceBundle.getBundle("resources.PolicyManager", loc);
            return rb;
        } else {
            return rb;
        }
    }
   
    /**
     * This method returns the current ResourceBundle which contains the
     * Strings of the messages that may be shown.
     * @return The actual ResourceBundle with message translations
     */
    public static ResourceBundle getMessageBundle() {
        if (mb == null) {
            mb = ResourceBundle.getBundle("resources.Messages", loc);
            return mb;
        } else {
            return mb;
        }
    }   
   
    /**
     * This method returns the ResourceBundle in which the Strings of the
     * components of the specified window are saved.
     * @param window A String with the name of the specified window
     * @param locale A Locale
     * @return The ResourceBundle which contains the Strings
     */
    public static ResourceBundle loadLanguageProps(String window, Locale locale) {
        ResourceBundle rb_temp = null;
        try {
            rb_temp = ResourceBundle.getBundle("resources." + window, locale);

        } catch (MissingResourceException mre) {
            System.out.println("Missing Resource Exception");
        }

        return rb_temp;
    }   

    /**
     * This method loads the specified File f into the DataBaseModel m
     * @param f A File which contains a policy database
     * @param m A DataBaseModel in which the data of the File should be saved
     */
    public static void readPolicyFile(File f, DataBaseModel m) {
        if (f == null) {
            return;
        }
       
        PolicyReader pr = new XMLPolicyReader();
        pr.loadPolicy(f, m);
    }

    /**
     * This method creates a line of a label on the left side and another
     * component on the right side which will be added to the forwarded
     * Container cont.
     * @param cont A Container in which the line should be placed
     * @param gbl A GridBagLayout
     * @param c1 A Label that will be placed on the left side
     * @param c2 A Component that will be placed on the right side
     * @param row The row in which the line should be added
     */
    public static void createLine(Container cont,
            GridBagLayout gbl,
            JLabel c1,
            Component c2,
            int row) {

        GridBagConstraints gbc = new GridBagConstraints();

        gbc.fill = GridBagConstraints.NONE;
        gbc.anchor = GridBagConstraints.EAST;
        gbc.gridx = 0;
        gbc.gridy = row;
        gbc.insets = new Insets(2, 2, 2, 5);
        gbc.weightx = 0.5;

        gbl.setConstraints(c1, gbc);
        cont.add(c1);

        if (c2 instanceof JScrollPane) {
            gbc.fill = GridBagConstraints.BOTH;
            gbc.gridheight = 3;
        } else {
            gbc.fill = GridBagConstraints.NONE;
        }
        gbc.anchor = GridBagConstraints.LINE_START;
        gbc.gridx = 1;
        gbc.gridy = row;
        gbc.insets = new Insets(2, 2, 2, 2);
        gbc.weightx = 0.5;

        gbl.setConstraints(c2, gbc);
        cont.add(c2);
    }

    /**
     * This method creates a line of a label on the left side and another
     * component on the right side which will be added to the forwarded
     * Container cont. It allows to define the insets of the line.
     * @param cont A Container in which the line should be placed
     * @param gbl A GridBagLayout
     * @param c1 A Label that will be placed on the left side
     * @param c2 A Component that will be placed on the right side
     * @param row The row in which the line should be added
     * @param topspace space between c1 and c2 and the component above them
     * @param bottomspace space between c1 and c2 and the component beneath them
     */
    public static void createLine(Container cont,
            GridBagLayout gbl,
            JLabel c1,
            Component c2,
            int row,
            int topspace,
            int bottomspace) {

        GridBagConstraints gbc = new GridBagConstraints();

        gbc.fill = GridBagConstraints.NONE;
        gbc.anchor = GridBagConstraints.EAST;
        gbc.gridx = 0;
        gbc.gridy = row;
        gbc.insets = new Insets(topspace, 2, bottomspace, 5);
        gbc.weightx = 0.5;

        gbl.setConstraints(c1, gbc);
        cont.add(c1);

        gbc.fill = GridBagConstraints.NONE;
        gbc.anchor = GridBagConstraints.LINE_START;
        gbc.gridx = 1;
        gbc.gridy = row;
        gbc.insets = new Insets(topspace, 2, bottomspace, 2);
        gbc.weightx = 0.5;

        gbl.setConstraints(c2, gbc);
        cont.add(c2);
    }

    /**
     * This method adds a component to a Container cont which will be anchored
     * with GridBagConstraints.NORTHWEST (top-left).
     * @param cont A container in which the component should be placed
     * @param gbl gbl A GridBagLayout
     * @param c A component that should be placed in the container
     * @param row The row in which the component should be placed
     * @param col The column in which the component should be placed
     * @param last A boolean that determines if the component should fill all of the space left
     */
    public static void addSwingCompWest(Container cont, GridBagLayout gbl, Component c, int row, int col, boolean last) {

        GridBagConstraints gbc = new GridBagConstraints();

        gbc.fill = GridBagConstraints.NONE;
        gbc.anchor = GridBagConstraints.NORTHWEST;
        gbc.gridx = col;
        gbc.gridy = row;
        gbc.weightx = 0.0;
        gbc.insets = new Insets(2, 5, 2, 15);
        gbc.gridheight = 1;
        if (last) {
            gbc.weighty = 1.0;
        }

        gbl.setConstraints(c, gbc);
        cont.add(c);
    }



    /**
     * This method creates a new ImageIcon out of the transmitted path.
     * @param path A String which contains the path to the resource
     * @return The generated ImageIcon
     */
    public static ImageIcon createImageIcon(String path) {
        java.net.URL imgURL = PolicyUtilities.class.getResource(path);

        return new ImageIcon(imgURL);
    }

    /**
     * This method transforms an int variable to a boolean variable. It returns
     * false for every int except 1.
     * @param i An int variable
     * @return A boolean variable
     */
    public static boolean intToBool(int i) {
        return (i == 1);
    }

    /**
     * This method transforms a boolean variable to an int variable. It returns
     * 1 if the boolean is true, else 0.
     * @param bool A boolean variable
     * @return An int variable
     */
    public static int boolToInt(boolean bool) {
        if (bool) {
            return 1;
        } else {
            return 0;
        }
    }
   
    /**
     * This method checks if the transferred PolicyModel fallback is a valid
     * fallback for the transferred PolicyModel parent. Returns true if valid,
     * else false
     * @param parent A PolicyModel
     * @param fallback A PolicyModel
     * @return A Boolean which indicates if the PolicyModel is valid
     */
    public static boolean isValidPolicyFallback(PolicyModel parent, PolicyModel fallback) {
        Set<PolicyModel> set = new HashSet<PolicyModel>();
        set.add(parent); // parent darf nicht auftauchen im zweig
        for (PolicyModel policy = fallback; policy != null; policy = policy.getFallback()) {
            if (policy.equals(policy.getFallback())) {
                return false; // oder eine Exception werfen
            }
            if (!set.add(policy)) {
                // policy gibt es bereits in dem set, also moegliche endlosschleife
                return false;
            }
        }
        return true;
    }
   
    /**
     * This method checks is a PolicyModel parent is a parent-policy to the also
     * transferred PolicyModel policy. It returns true if it is, else false.
     * @param parent A PolicyModel
     * @param policy A PolicyModel
     * @return A boolean which indicates if the PolicyModel is parent
     */
    public static boolean isParentPolicy(PolicyModel parent, PolicyModel policy) {
        if(parent.getFallback() != null)
            if(parent.getFallback().equals(policy))
                return true;
        return false;
    }
   
    /**
     * This method returns the parent-policy of the transferred policy. If no
     * policy exists it returns null.
     * @param policy A PolicyModel of which the parent should be found
     * @param policies A List which includes all the policies
     * @return A PolicyModel which is the parent-policy or null
     */
    public static PolicyModel getParentPolicy(PolicyModel policy, List<PolicyModel> policies) {
        for(int i=0; i<policies.size(); i++) {
            PolicyModel parent = policies.get(i);
            PolicyModel fb = parent.getFallback();
            if((fb != null) && (fb.equals(policy)))
                return parent;
        }      
        return null;
    }

    /**
     * This method returns an integer with the next free id for a new
     * application.
     * @return An int with an id
     */
    public static int getNewApplicationId() {
        Set<Integer> appKeys = dbModel.getAppKeys();
        int id = 0;

        for (Integer i : appKeys) {
            if (i.intValue() == id) {
                id++;
            } else {
                return id;
            }
        }

        return appKeys.size();
    }

    /**
     * This method returns an integer with the next free id for a new
     * receiverlist.
     * @return An int with an id
     */
    public static int getNewReceiverListId() {
        Set<Integer> receiverListKeys = dbModel.getReceiverListKeys();
        int id = 0;

        for (Integer i : receiverListKeys) {
            if (i.intValue() == id) {
                id++;
            } else {
                return id;
            }
        }
        return receiverListKeys.size();
    }

    /**
     * This method returns an integer with the next free id for a new policy.
     * @return An int with an id
     */
    public static int getNewPolicyId() {
        Set<Integer> policyKeys = null;
        switch (dbModel.getActiveLevel()) {
            case A:
                policyKeys = dbModel.getPolicyAKeys();
                break;
            case C:
                policyKeys = dbModel.getPolicyCKeys();
                break;
            case I:
                policyKeys = dbModel.getPolicyIKeys();
                break;
        }
        int id = 0;

        for (Integer i : policyKeys) {
            if (i.intValue() == id) {
                id++;
            } else {
                return id;
            }
        }
        return policyKeys.size();
    }

    /**
     * This method returns an integer with the next free id for a new receiver.
     * @return An int with an id
     */
    public static int getNewReceiverId() {
        List<ReceiverModel> receivers = dbModel.getCurrentReceiverList().getReceivers();
        Set<Integer> receiverKeys = new TreeSet();

        for (ReceiverModel rm : receivers) {
            receiverKeys.add(rm.getId());
        }

        int id = 0;

        for (Integer i : receiverKeys) {
            if (i.intValue() == id) {
                id++;
            } else {
                return id;
            }
        }
        return receiverKeys.size();
    }

    /**
     * This method sets the ranks of the policies which are stored in the
     * transferred List. If the also transferred boolean refresh is true then
     * the updated list will be stored in the DataBaseModel.
     * @param list A List that includes the policies
     * @param refresh A boolean
     */
    public static void setPolicyRanks(List<PolicyModel> list, boolean refresh) {
        int size = list.size();
        int current = size;
        for (int i = 0; i < size; i++) {
            PolicyModel p = list.get(i);

            if(getParentPolicy(p, list) == null) {             
                for(; p != null; p = p.getFallback()) {
                    p.setRank(current);
                    current--;   
                }
            }
        }

        if(refresh) {
            switch (dbModel.getActiveLevel()) {
                case A:
                    list = dbModel.getAPolicies();
                    break;
                case C:
                    list = dbModel.getCPolicies();
                    break;
                case I:
                    list = dbModel.getIPolicies();
                    break;
            }
        }
        Collections.sort(list);
        Collections.reverse(list);
    }

    /**
     * This method creates an XML-String out of the DataBaseModel
     * @return A String
     */
    public static String createSystemStateString(DataBaseModel model) {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            XMLEncoder xmlEncoder = new XMLEncoder(outputStream);
            xmlEncoder.setPersistenceDelegate(ActionModel.class, new DefaultPersistenceDelegate(new String[]{"actions","id"}));
            xmlEncoder.setPersistenceDelegate(ActionTupel.class, new DefaultPersistenceDelegate(new String[]{"algorithm","mode"}));
            xmlEncoder.writeObject(model);
            xmlEncoder.close();
            outputStream.close();

            return outputStream.toString();
        } catch (IOException ex) {
            Logger.getLogger(PolicyUtilities.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    /**
     * This method checks if the systemState has been changed. Returns true if it
     * has, else false.
     * @return A boolean variable
     */
    public static boolean isStateChanged() {
        String newState = createSystemStateString(dbModel);
        boolean changed = !systemState.equals(newState);
        return changed;
    }
   
    public static void setSystemState(String state) {
        PolicyUtilities.systemState = state;
    }

    /**
     * This message shows a MessageDialog.
     * @param message A String that contains the message
     * @param type A JOptionPane.MessageType
     * @return An int variable with the result of the dialog
     */
    public static int showMessageDialog(String message, int type) {
        int i = -1;
        switch (type) {
            case JOptionPane.WARNING_MESSAGE:
                JOptionPane.showMessageDialog(null, message, rb.getString("warning"), JOptionPane.WARNING_MESSAGE);
                break;
            case JOptionPane.ERROR_MESSAGE:
                JOptionPane.showMessageDialog(null, message, rb.getString("error"), JOptionPane.ERROR_MESSAGE);
                break;
            case JOptionPane.INFORMATION_MESSAGE:
                JOptionPane.showMessageDialog(null, message, rb.getString("information"), JOptionPane.INFORMATION_MESSAGE);
                break;
            case JOptionPane.QUESTION_MESSAGE:
                i = JOptionPane.showConfirmDialog(null, message, rb.getString("warning"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
                break;
        }
       
        return i;
    }
   
    /**
     * This method sets the boolean "show" which indicates if warnings should be
     * displayed or not.
     * @param show A boolean variable
     */
    public static void setShowWarnings(boolean show) {
        showWarnings = show;
    }
   
    /**
     * This method returns a boolean which indicates if warnings should be shown
     * or not. Returns true if warnings should be shown, else false.
     * @return A boolean variable
     */
    public static boolean isShowWarnings() {
        return showWarnings;
    }
   
    /**
     * This method replaces placeholders in messages with content.
     * @param replace A String which contains the content.
     * @param message A String with the message that contains the placeholder.
     * @return A String containing the message with replaced content
     */
    public static String replacePlaceHolder(String replace, String message) {
        String str2 = message.replaceFirst("<placeholder>", replace);
        return str2;
    }
   
    /**
     * This method returns a PolicyModel which only is used to display that
     * no policy has been selected. It will not be saved in the database.
     * @return A PolicyModel
     */
    public static PolicyModel getDummyPolicy() {
        PolicyModel dummy = new PolicyModel();
        dummy.setName(rb.getString("nopolicy"));
        dummy.setId(13377331);
       
        return dummy;
    }

  public static MethodResult sign(byte[] data2beSigned,
                  String keyStorePath,
                  char[] keyStorePassword,
                  String keyAlias,
                  char[] privateKeyPassword,
                  String digestOID) {
    KeyStore keyStore = null;
    Key privateKey;
    CMSSignedDataGenerator generator;
    CMSProcessable processableData;
    CMSSignedData signedContainer;
    MethodResult loadingKeyStoreResult;

    MethodResult signingDataResult;
    byte[] signedData = null;
    int resultValue = UNKNOWN_ERROR;
    Throwable th = null;

    loadingKeyStoreResult = loadKeyStore(keyStorePath, keyStorePassword);
//    Log.d(TAG, "keystore: " + loadingKeyStoreResult.getResultObject());

    if (loadingKeyStoreResult.getResultValue() == OPERATION_SUCCESSFUL) {
      try {
        keyStore = (KeyStore) loadingKeyStoreResult.getResultObject();
        privateKey = keyStore.getKey(keyAlias, privateKeyPassword);
        generator = new CMSSignedDataGenerator();
        generator.addSigner((PrivateKey) privateKey,
                    (X509Certificate) keyStore.getCertificate(keyAlias),
                    digestOID);
        List<X509Certificate> certList = new ArrayList<X509Certificate>();
        certList.add((X509Certificate) keyStore.getCertificate(keyAlias));
        CertStoreParameters params = new CollectionCertStoreParameters(certList);
        CertStore cs = CertStore.getInstance("Collection", params, "BC");
        generator.addCertificatesAndCRLs(cs);
        processableData = new CMSProcessableByteArray(data2beSigned);
        signedContainer = generator.generate(processableData, true, "BC");
        signedData = signedContainer.getEncoded();
        resultValue = OPERATION_SUCCESSFUL;
      } catch (UnrecoverableKeyException uke) {
        uke.printStackTrace();
        resultValue = PRIVATE_KEY_CORRUPTED;
        th = uke;
      } catch (KeyStoreException kse) {
        kse.printStackTrace();
        resultValue = KEYSTORE_CORRUPTED;
        th = kse;
      } catch (NoSuchAlgorithmException nsae) {
        nsae.printStackTrace();
        resultValue = ALGORITHM_NOT_FOUND;
        th = nsae;
      } catch (InvalidAlgorithmParameterException iape) {
        iape.printStackTrace();
        resultValue = ALGORITHM_NOT_FOUND;
        th = iape;
      } catch (NoSuchProviderException nspe) {
        nspe.printStackTrace();
        resultValue = CRYPTO_PROVIDER_NOT_FOUND;
        th = nspe;
      } catch (CertStoreException cse) {
        cse.printStackTrace();
        resultValue = CERTIFICATE_CORRUPTED;
        th = cse;
      } catch (CMSException cmse) {
        cmse.printStackTrace();
        resultValue = MESSAGE_CORRUPTED;
        th = cmse;
      } catch (IOException ioe) {
        ioe.printStackTrace();
        resultValue = IO_ERROR;
        th = ioe;
      } catch (Throwable t) {
        t.printStackTrace();
        resultValue = UNKNOWN_ERROR;
        th = t;
      }
    }
    else { // loading of keystore was not successful...
      resultValue = loadingKeyStoreResult.getResultValue();
      th = loadingKeyStoreResult.getT();
    }

    signingDataResult = new MethodResult(resultValue, signedData, th);

    return signingDataResult;
  }

  private static MethodResult loadKeyStore(String keyStorePath, char[] keyStorePassword) {
    MethodResult result;
    int resultValue = UNKNOWN_ERROR;
    Throwable th = null;

    MethodResult gettingKeyStoreContentResult;

    File keyStoreFile;
    InputStream signedKeyStoreInputStream;
    KeyStore keyStore = null;

    try {
      keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
      keyStoreFile = new File(keyStorePath);
      signedKeyStoreInputStream = new FileInputStream(keyStoreFile);
      gettingKeyStoreContentResult = getContentOfSignedData(signedKeyStoreInputStream, true);

      if (gettingKeyStoreContentResult.getResultValue() == OPERATION_SUCCESSFUL) {
        keyStore.load((InputStream) gettingKeyStoreContentResult.getResultObject(), keyStorePassword);
        // XXX close the inputstream possible after loading the keystore ?
//        Log.d(TAG, "keystore: " + keyStore);
        resultValue = OPERATION_SUCCESSFUL;
      }
      else {
        resultValue = gettingKeyStoreContentResult.getResultValue();
        th = gettingKeyStoreContentResult.getT();
      }

    } catch (KeyStoreException kse) {
      kse.printStackTrace();
      resultValue = KEYSTORE_CORRUPTED;
      th = kse;
    } catch (FileNotFoundException fne) {
      fne.printStackTrace();
      resultValue = KEYSTORE_NOT_FOUND;
      th = fne;
    } catch (NoSuchAlgorithmException nsae) {
      nsae.printStackTrace();
      resultValue = ALGORITHM_NOT_FOUND;
      th = nsae;
    } catch (CertificateException ce) {
      ce.printStackTrace();
      resultValue = CERTIFICATE_CORRUPTED;
      th = ce;
    } catch (IOException ioe) {
      ioe.printStackTrace();
      resultValue = IO_ERROR;
      th = ioe;
    } catch (Throwable t) {
      t.printStackTrace();
      resultValue = UNKNOWN_ERROR;
      th = t;
    }

    result = new MethodResult(resultValue, keyStore, th);

    return result;
  }

  public static MethodResult getContentOfSignedData (InputStream signedContentStream, boolean resultAsStream) {
    MethodResult result = null;
    int resultValue = 0;
    byte[] content = null;
    Throwable th = null;

    CMSSignedData signedData;
    ByteArrayInputStream contentStream = null;

    try {
      signedData = new CMSSignedData(signedContentStream);
      content = (byte[]) signedData.getSignedContent().getContent();

      if (resultAsStream)
        contentStream = new ByteArrayInputStream(content);

      resultValue = OPERATION_SUCCESSFUL;
    } catch (CMSException cmse) {
      cmse.printStackTrace();
      resultValue = MESSAGE_CORRUPTED;
      th = cmse;
    } catch (Throwable t) {
      t.printStackTrace();
      resultValue = UNKNOWN_ERROR;
      th = t;
    }

    if (resultAsStream)
      result = new MethodResult(resultValue, contentStream, th);
    else
      result = new MethodResult(resultValue, content, th);

    return result;
  }
}
TOP

Related Classes of de.netsysit.policymanager.PolicyUtilities

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.