package won.owner.model;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Entity
@Table(name = "keystore")
public class KeystoreHolder {
	private static final int DEFAULT_BYTE_ARRAY_SIZE = 500;
	
	private static final String PROVIDER_BC = org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
	private static final String KEY_STORE_TYPE = "UBER";


    @Id
    @GeneratedValue
    @Column(name = "id")
    private Long id;
    
    @Transient
    private final Logger logger = LoggerFactory.getLogger(getClass());


    //the keystore as a byte array
    @Lob
    @Column(name = "keystore_data", nullable = false, length = 10000000)
    private byte[] keystoreBytes;


    public KeystoreHolder() {
		super();
	}

	public Long getId() {
        return id;
    }

    public void setId(final Long id) {
        this.id = id;
    }

    public void setKeystoreBytes(byte[] keystoreBytes) {
		this.keystoreBytes = keystoreBytes;
	}

    public byte[] getKeystoreBytes() {
		return keystoreBytes;
	}
    
    /**
     * Careful, expensive operation: writes dataset to string.
     *
     * @param dataset
     * @throws IOException 
     */
    public synchronized void setKeystore(KeyStore store, String password) throws IOException {
        synchronized (this) {
        	ByteArrayOutputStream outputStream = new ByteArrayOutputStream(DEFAULT_BYTE_ARRAY_SIZE);
    		if (outputStream != null) {
    			try {
    				store.store(outputStream, password.toCharArray());
    				this.keystoreBytes = outputStream.toByteArray();
    			} catch (Exception e) {
    				logger.error("Could not save key store "  + getId(), e);
    				throw new IOException(e);
    			} finally {
    				try {
    					outputStream.close();
    				} catch (Exception e) {
    					logger.error("Error closing stream of keystore "  + getId(), e);
    					throw e;
    				}
    			}
    		}
        }
    }

    public synchronized KeyStore getKeystore(String password) throws Exception {
    	KeyStore store = null;
    	InputStream inputStream = null;
    	byte[] keystoreData = getKeystoreBytes();
    	if (keystoreData == null || keystoreData.length == 0) {
    		//return a new, empty key store if there is no key store yet.
			store = java.security.KeyStore.getInstance(KEY_STORE_TYPE, PROVIDER_BC);
			store.load(null, password.toCharArray());
			//also set this key store so we can save it to db. (hence the synchronized methods)
			setKeystore(store, password);
			return store;
    	}
    	inputStream = new ByteArrayInputStream(getKeystoreBytes());
		try {
			store = java.security.KeyStore.getInstance(KEY_STORE_TYPE, PROVIDER_BC);
			store.load(inputStream, password.toCharArray());
		} catch (Exception e) {
			logger.error("Could not load key store "  + getId(), e);
			throw e;
		} finally {
			try {
				inputStream.close();
			} catch (Exception e) {
				logger.error("Error closing stream of keystore " + getId(), e);
				throw e;
			}

		}
		return store;
    }
}

@@ -187,16 +187,65 @@
 yStore;%0D
+%0Aimport java.security.cert.CertificateException;%0D
 %0A%0D%0Aimpor
@@ -1746,24 +1746,32 @@
 ord) throws 
+KeyStore
 IOException 
@@ -2186,16 +2186,24 @@
 row new 
+KeyStore
 IOExcept
@@ -2206,16 +2206,54 @@
 ception(
+%22Could not save keystore %22 + getId(), 
 e);%0D%0A   
@@ -2439,17 +2439,89 @@
 %09%09throw 
-e
+new KeyStoreIOException(%22Error closing stream of keystore %22 + getId(), e)
 ;%0D%0A    %09
@@ -2634,16 +2634,26 @@
  throws 
+KeyStoreIO
 Exceptio
@@ -2903,16 +2903,36 @@
 e yet.%0D%0A
+    %09    try %7B%0D%0A    
 %09%09%09store
@@ -2992,32 +2992,36 @@
  PROVIDER_BC);%0D%0A
+    
 %09%09%09store.load(nu
@@ -3050,16 +3050,20 @@
 ay());%0D%0A
+    
 %09%09%09//als
@@ -3142,16 +3142,20 @@
 thods)%0D%0A
+    
 %09%09%09setKe
@@ -3180,16 +3180,20 @@
 word);%0D%0A
+    
 %09%09%09retur
@@ -3198,24 +3198,160 @@
 urn store;%0D%0A
+    %09    %7D catch (Exception e) %7B%0D%0A    %09        throw new KeyStoreIOException(%22Could not load keystore %22 + getId(), e);    %0D%0A    %09    %7D%0D%0A
     %09%7D%0D%0A    
@@ -3644,25 +3644,88 @@
 ;%0D%0A%09%09%09throw 
-e
+new KeyStoreIOException(%22Could not load keystore %22 + getId(), e)
 ;%0D%0A%09%09%7D final
@@ -3873,17 +3873,89 @@
 %09%09throw 
-e
+new KeyStoreIOException(%22Error closing stream of keystore %22 + getId(), e)
 ;%0D%0A%09%09%09%7D%0D

Throw more specific exception for loading and writing keyStore