From 772bbeb2713e745c08ecbcbbf365ecc767ecbf16 Mon Sep 17 00:00:00 2001 From: Henri Herscher Date: Wed, 21 Dec 2005 03:59:04 +0000 Subject: Starting to add business objects and services git-svn-id: https://oreka.svn.sourceforge.net/svnroot/oreka/trunk@111 09dcff7a-b715-0410-9601-b79a96267cd0 --- orkbasej/java/net/sf/oreka/HibernateManager.java | 11 + orkbasej/java/net/sf/oreka/OrkBase.java | 32 + orkbasej/java/net/sf/oreka/OrkTest.java | 2 +- orkbasej/java/net/sf/oreka/bo/UserBo.java | 32 + orkbasej/java/net/sf/oreka/persistent/User.java | 2 +- .../net/sf/oreka/serializers/DomSerializer.java | 24 +- .../oreka/serializers/test/DomSerializerTest.java | 2 +- orkbasej/java/net/sf/oreka/srvc/UserService.java | 10 + .../java/net/sf/oreka/srvc/UserServiceHbn.java | 102 ++ orkbasej/java/net/sf/oreka/test/FillDatabase.java | 2 +- orkbasej/java/net/sf/oreka/util/Base64.java | 1071 ++++++++++++++++++++ 11 files changed, 1271 insertions(+), 19 deletions(-) create mode 100644 orkbasej/java/net/sf/oreka/OrkBase.java create mode 100644 orkbasej/java/net/sf/oreka/bo/UserBo.java create mode 100644 orkbasej/java/net/sf/oreka/srvc/UserService.java create mode 100644 orkbasej/java/net/sf/oreka/srvc/UserServiceHbn.java create mode 100644 orkbasej/java/net/sf/oreka/util/Base64.java (limited to 'orkbasej') diff --git a/orkbasej/java/net/sf/oreka/HibernateManager.java b/orkbasej/java/net/sf/oreka/HibernateManager.java index 6fa5b7f..f154db6 100644 --- a/orkbasej/java/net/sf/oreka/HibernateManager.java +++ b/orkbasej/java/net/sf/oreka/HibernateManager.java @@ -43,9 +43,20 @@ import org.logicalcobwebs.proxool.ProxoolFacade; public class HibernateManager { + private static HibernateManager hibernateManager = null; private SessionFactory sessionFactory = null; static Logger logger = Logger.getLogger(HibernateManager.class); + private HibernateManager() { + } + + public static HibernateManager instance() { + if(hibernateManager == null) { + hibernateManager = new HibernateManager(); + } + return hibernateManager; + } + public void configure(String filename) throws Exception { File configFile = new File(filename); diff --git a/orkbasej/java/net/sf/oreka/OrkBase.java b/orkbasej/java/net/sf/oreka/OrkBase.java new file mode 100644 index 0000000..72610e7 --- /dev/null +++ b/orkbasej/java/net/sf/oreka/OrkBase.java @@ -0,0 +1,32 @@ +package net.sf.oreka; + + + +public class OrkBase { + + private static OrkBase orkBase = null; + + private boolean debugSwitch = false; + + public boolean isDebugSwitch() { + return debugSwitch; + } + + + public void setDebugSwitch(boolean debugSwitch) { + this.debugSwitch = debugSwitch; + } + + + private OrkBase() { + } + + public static OrkBase instance() { + if(orkBase == null) { + orkBase = new OrkBase(); + } + return orkBase; + } + + +} diff --git a/orkbasej/java/net/sf/oreka/OrkTest.java b/orkbasej/java/net/sf/oreka/OrkTest.java index c08ec1e..bda8b72 100644 --- a/orkbasej/java/net/sf/oreka/OrkTest.java +++ b/orkbasej/java/net/sf/oreka/OrkTest.java @@ -113,7 +113,7 @@ public class OrkTest { // System.out.println(DomSerializer.NodeToString(doc)); ser.serialize(doc, el, msg); - System.out.println(DomSerializer.NodeToString(doc)); + System.out.println(DomSerializer.nodeToByteArray(doc).toString()); TestNestedMessage tnm = new TestNestedMessage(); TestSubMessage tsm = tnm.getSubMsg(); diff --git a/orkbasej/java/net/sf/oreka/bo/UserBo.java b/orkbasej/java/net/sf/oreka/bo/UserBo.java new file mode 100644 index 0000000..2751d2f --- /dev/null +++ b/orkbasej/java/net/sf/oreka/bo/UserBo.java @@ -0,0 +1,32 @@ +package net.sf.oreka.bo; + +import org.apache.log4j.Logger; + +import net.sf.oreka.persistent.User; +import net.sf.oreka.srvc.UserServiceHbn; + +public class UserBo { + + static Logger logger = Logger.getLogger(UserBo.class); + private User user = new User(); + + public boolean isAdmin() { + + //logger.debug("isAdmin:" + user.getId()); + + // Should look for admin role + if(user.getId() == 1) { + return true; + } + return false; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + +} diff --git a/orkbasej/java/net/sf/oreka/persistent/User.java b/orkbasej/java/net/sf/oreka/persistent/User.java index 5d78760..45fa9ad 100644 --- a/orkbasej/java/net/sf/oreka/persistent/User.java +++ b/orkbasej/java/net/sf/oreka/persistent/User.java @@ -26,7 +26,7 @@ import javax.persistence.Id; @Entity public class User { - private int id; + private int id = 0; private String password = ""; private String firstname = ""; private String lastname = ""; diff --git a/orkbasej/java/net/sf/oreka/serializers/DomSerializer.java b/orkbasej/java/net/sf/oreka/serializers/DomSerializer.java index ac64a13..53d7605 100644 --- a/orkbasej/java/net/sf/oreka/serializers/DomSerializer.java +++ b/orkbasej/java/net/sf/oreka/serializers/DomSerializer.java @@ -20,6 +20,7 @@ import java.io.ByteArrayOutputStream; import javax.xml.transform.Result; import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; @@ -164,23 +165,16 @@ public class DomSerializer extends OrkSerializer { return null; } - public static String NodeToString(Node node) { + public static byte[] nodeToByteArray(Node node) throws TransformerException { - String result = null; TransformerFactory xformerFactory = TransformerFactory.newInstance(); - try { - Transformer xformer = xformerFactory.newTransformer(); - xformer.setOutputProperty("indent", "yes"); - ByteArrayOutputStream byteArray = new ByteArrayOutputStream(); - Result output = new StreamResult(byteArray); - DOMSource source = new DOMSource(node); - xformer.transform(source,output); - result = byteArray.toString(); - } - catch (Exception e) { - ; - } - return result; + Transformer xformer = xformerFactory.newTransformer(); + xformer.setOutputProperty("indent", "yes"); + ByteArrayOutputStream byteArray = new ByteArrayOutputStream(); + Result output = new StreamResult(byteArray); + DOMSource source = new DOMSource(node); + xformer.transform(source,output); + return byteArray.toByteArray(); } } diff --git a/orkbasej/java/net/sf/oreka/serializers/test/DomSerializerTest.java b/orkbasej/java/net/sf/oreka/serializers/test/DomSerializerTest.java index 198da4d..0fbf6d1 100644 --- a/orkbasej/java/net/sf/oreka/serializers/test/DomSerializerTest.java +++ b/orkbasej/java/net/sf/oreka/serializers/test/DomSerializerTest.java @@ -74,7 +74,7 @@ public class DomSerializerTest extends TestCase { DomSerializer ser = new DomSerializer(); ser.serialize(doc, docNode, tnm); - //System.out.println(DomSerializer.NodeToString(doc)); + System.out.println(DomSerializer.nodeToByteArray(doc).toString()); OrkObject obj = ser.deSerialize(docNode); assertTrue(((TestNestedMessage)obj).getDoubleParm() == 0.666); assertTrue(((TestNestedMessage)obj).getSubMsg().getStringSubParm() == "le maure"); diff --git a/orkbasej/java/net/sf/oreka/srvc/UserService.java b/orkbasej/java/net/sf/oreka/srvc/UserService.java new file mode 100644 index 0000000..0b2b17e --- /dev/null +++ b/orkbasej/java/net/sf/oreka/srvc/UserService.java @@ -0,0 +1,10 @@ +package net.sf.oreka.srvc; + +import net.sf.oreka.bo.UserBo; + +public interface UserService { + + public UserBo login(String username, String password); + public boolean changePassword(int userId, String oldPassword, String newPassword); + +} diff --git a/orkbasej/java/net/sf/oreka/srvc/UserServiceHbn.java b/orkbasej/java/net/sf/oreka/srvc/UserServiceHbn.java new file mode 100644 index 0000000..71a2a0c --- /dev/null +++ b/orkbasej/java/net/sf/oreka/srvc/UserServiceHbn.java @@ -0,0 +1,102 @@ +package net.sf.oreka.srvc; + +import java.util.ArrayList; + +import net.sf.oreka.HibernateManager; +import net.sf.oreka.OrkBase; +import net.sf.oreka.bo.UserBo; +import net.sf.oreka.persistent.User; + +import org.apache.log4j.Logger; +import org.hibernate.HibernateException; +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.Transaction; + +public class UserServiceHbn implements UserService { + + static Logger logger = Logger.getLogger(UserServiceHbn.class); + + public UserBo login(String username, String password) { + + Session hbnSession = null; + UserBo userBo = null; + + logger.debug("Trying to login user:" + username + " with passwd:" + password); + + try + { + hbnSession = HibernateManager.instance().getSession(); + + String queryString = new String("from LoginString as ls left join ls.user as user where ls.loginString=:ls"); + if (OrkBase.instance().isDebugSwitch() == false) { + queryString = queryString + " and user.password=:password"; + } + Query query = hbnSession.createQuery(queryString); + query.setString("ls", username); + if (OrkBase.instance().isDebugSwitch() == false) { + query.setString("password", password); + } + ArrayList results = (ArrayList)query.list(); + Object[] row = (Object[])query.uniqueResult(); + if (row != null) { + userBo = new UserBo(); + userBo.setUser((User)row[1]); + logger.debug("Found userid:" + userBo.getUser().getId() + " for login string:" + username); + } + } + catch ( HibernateException he ) { + logger.error("login: exception:" + he.getClass().getName()); + } + catch (Exception e) + { + logger.error("login: exception:", e); + } + finally { + if(hbnSession != null) {hbnSession.close();} + } + return userBo; + } + + public boolean changePassword(int userId, String oldPassword, String newPassword) { + + Session hbnSession = null; + Transaction tx = null; + User user = null; + boolean success = false; + + logger.debug("Trying to change password for userid:" + userId); + + try + { + hbnSession = HibernateManager.instance().getSession(); + + + user = (User)hbnSession.get(User.class, userId); + if(user == null) { + logger.warn("Userid:" + userId + " does not exist"); + } + else { + if(user.getPassword().equals(oldPassword)) { + tx = hbnSession.beginTransaction(); + user.setPassword(newPassword); + hbnSession.save(user); + tx.commit(); + success = true; + logger.debug("Changed password for userid:" + userId); + } + } + } + catch ( HibernateException he ) { + logger.error("changePassword: exception:" + he.getClass().getName()); + } + catch (Exception e) + { + logger.error("changePassword: exception:", e); + } + finally { + if(hbnSession != null) {hbnSession.close();} + } + return success; + } +} diff --git a/orkbasej/java/net/sf/oreka/test/FillDatabase.java b/orkbasej/java/net/sf/oreka/test/FillDatabase.java index 1bef840..0b0596c 100644 --- a/orkbasej/java/net/sf/oreka/test/FillDatabase.java +++ b/orkbasej/java/net/sf/oreka/test/FillDatabase.java @@ -29,7 +29,7 @@ import org.hibernate.Transaction; public class FillDatabase { - static HibernateManager hibernateManager = new HibernateManager(); + static HibernateManager hibernateManager = HibernateManager.instance(); public static void main(String args[]) throws Exception { diff --git a/orkbasej/java/net/sf/oreka/util/Base64.java b/orkbasej/java/net/sf/oreka/util/Base64.java new file mode 100644 index 0000000..7da1ffd --- /dev/null +++ b/orkbasej/java/net/sf/oreka/util/Base64.java @@ -0,0 +1,1071 @@ +/* + * Base64.java + * + * This code is Public Domain, see the comments below for more details. + * + */ + +package net.sf.oreka.util; + +/** + * Encodes and decodes to and from Base64 notation. + * + *

+ * Change Log: + *

+ * + * + *

+ * I am placing this code in the Public Domain. Do with it as you will. + * This software comes with no guarantees or warranties but with + * plenty of well-wishing instead! + * Please visit http://iharder.net/xmlizable + * periodically to check for updates or to contribute improvements. + *

+ * + * @author Robert Harder + * @author rob@iharder.net + * @version 1.3.4 + */ +public class Base64 +{ + + /** Specify encoding (value is true). */ + public final static boolean ENCODE = true; + + + /** Specify decoding (value is false). */ + public final static boolean DECODE = false; + + + /** Maximum line length (76) of Base64 output. */ + private final static int MAX_LINE_LENGTH = 76; + + + /** The equals sign (=) as a byte. */ + private final static byte EQUALS_SIGN = (byte)'='; + + + /** The new line character (\n) as a byte. */ + private final static byte NEW_LINE = (byte)'\n'; + + + /** The 64 valid Base64 values. */ + private final static byte[] ALPHABET = + { + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', + (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/' + }; + + /** + * Translates a Base64 value to either its 6-bit reconstruction value + * or a negative number indicating some other meaning. + **/ + final static byte[] DECODABET = + { + -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 + -5,-5, // Whitespace: Tab and Linefeed + -9,-9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 + -9,-9,-9,-9,-9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 + 62, // Plus sign at decimal 43 + -9,-9,-9, // Decimal 44 - 46 + 63, // Slash at decimal 47 + 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine + -9,-9,-9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9,-9,-9, // Decimal 62 - 64 + 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N' + 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z' + -9,-9,-9,-9,-9,-9, // Decimal 91 - 96 + 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm' + 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z' + -9,-9,-9,-9 // Decimal 123 - 126 + /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + //private final static byte BAD_ENCODING = -9; // Indicates error in encoding + private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding + private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding + + + /** Defeats instantiation. */ + private Base64 (){} + + +/* ******** E N C O D I N G M E T H O D S ******** */ + + + /** + * Encodes the first three bytes of array threeBytes + * and returns a four-byte array in Base64 notation. + * + * @param threeBytes the array to convert + * @return four byte array in Base64 notation. + * @since 1.3 + */ + + protected static byte[] encode3to4( byte[] threeBytes ) + { return encode3to4( threeBytes, 3 ); + } // end encodeToBytes + + + + /** + * Encodes up to the first three bytes of array threeBytes + * and returns a four-byte array in Base64 notation. + * The actual number of significant bytes in your array is + * given by numSigBytes. + * The array threeBytes needs only be as big as + * numSigBytes. + * + * @param threeBytes the array to convert + * @param numSigBytes the number of significant bytes in your array + * @return four byte array in Base64 notation. + * @since 1.3 + */ + static byte[] encode3to4( byte[] threeBytes, int numSigBytes ) + { byte[] dest = new byte[4]; + encode3to4( threeBytes, 0, numSigBytes, dest, 0 ); + return dest; + } + + + + /** + * Encodes up to three bytes of the array source + * and writes the resulting four Base64 bytes to destination. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * srcOffset and destOffset. + * This method does not check to make sure your arrays + * are large enough to accomodate srcOffset + 3 for + * the source array or destOffset + 4 for + * the destination array. + * The actual number of significant bytes in your array is + * given by numSigBytes. + * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param numSigBytes the number of significant bytes in your array + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @return the destination array + * @since 1.3 + */ + static byte[] encode3to4( + byte[] source, int srcOffset, int numSigBytes, + byte[] destination, int destOffset ) + { + // 1 2 3 + // 01234567890123456789012345678901 Bit position + // --------000000001111111122222222 Array position from threeBytes + // --------| || || || | Six bit groups to index ALPHABET + // >>18 >>12 >> 6 >> 0 Right shift necessary + // 0x3f 0x3f 0x3f Additional AND + + // Create buffer with zero-padding if there are only one or two + // significant bytes passed in the array. + // We have to shift left 24 in order to flush out the 1's that appear + // when Java treats a value as negative that is cast from a byte to an int. + int inBuff = ( numSigBytes > 0 ? ((source[ srcOffset ] << 24) >>> 8) : 0 ) + | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 ) + | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 ); + + switch( numSigBytes ) + { + case 3: + destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; + destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; + destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ]; + destination[ destOffset + 3 ] = ALPHABET[ (inBuff ) & 0x3f ]; + return destination; + + case 2: + destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; + destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; + destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ]; + destination[ destOffset + 3 ] = EQUALS_SIGN; + return destination; + + case 1: + destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; + destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; + destination[ destOffset + 2 ] = EQUALS_SIGN; + destination[ destOffset + 3 ] = EQUALS_SIGN; + return destination; + + default: + return destination; + } // end switch + } // end encode3to4 + + /** + * Serializes an object and returns the Base64-encoded + * version of that serialized object. If the object + * cannot be serialized or there is another error, + * the method will return null. + * + * @param serializableObject The object to encode + * @return The Base64-encoded object + * @since 1.4 + */ + public static String encodeObject( java.io.Serializable serializableObject ) + { + return encodeObject( serializableObject, true ); + } // end encodeObject + + /** + * Serializes an object and returns the Base64-encoded + * version of that serialized object. If the object + * cannot be serialized or there is another error, + * the method will return null. + * + * @param serializableObject The object to encode + * @param breakLines Break lines at 80 characters or less. + * @return The Base64-encoded object + * @since 1.4 + */ + public static String encodeObject( java.io.Serializable serializableObject, boolean breakLines ) + { + java.io.ByteArrayOutputStream baos = null; + java.io.OutputStream b64os = null; + java.io.ObjectOutputStream oos = null; + + try + { + baos = new java.io.ByteArrayOutputStream(); + b64os = new Base64.OutputStream( baos, Base64.ENCODE, breakLines ); + oos = new java.io.ObjectOutputStream( b64os ); + + oos.writeObject( serializableObject ); + } // end try + catch( java.io.IOException e ) + { + e.printStackTrace(); + return null; + } // end catch + finally + { + try{ oos.close(); } catch( Exception e ){} + try{ b64os.close(); } catch( Exception e ){} + try{ baos.close(); } catch( Exception e ){} + } // end finally + + return new String( baos.toByteArray() ); + } // end encode + + + /** + * Encodes a byte array into Base64 notation. + * Equivalen to calling + * encodeBytes( source, 0, source.length ) + * + * @param source The data to convert + * @since 1.4 + */ + public static String encodeBytes( byte[] source ) + { + return encodeBytes( source, true ); + } // end encodeBytes + + /** + * Encodes a byte array into Base64 notation. + * Equivalen to calling + * encodeBytes( source, 0, source.length ) + * + * @param source The data to convert + * @param breakLines Break lines at 80 characters or less. + * @since 1.4 + */ + public static String encodeBytes( byte[] source, boolean breakLines ) + { + return encodeBytes( source, 0, source.length, breakLines ); + } // end encodeBytes + + + /** + * Encodes a byte array into Base64 notation. + * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @since 1.4 + */ + public static String encodeBytes( byte[] source, int off, int len ) + { + return encodeBytes( source, off, len, true ); + } // end encodeBytes + + + /** + * Encodes a byte array into Base64 notation. + * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @param breakLines Break lines at 80 characters or less. + * @since 1.4 + */ + public static String encodeBytes( byte[] source, int off, int len, boolean breakLines ) + { + int len43 = len * 4 / 3; + byte[] outBuff = new byte[ ( len43 ) // Main 4:3 + + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding + + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines + int d = 0; + int e = 0; + int len2 = len - 2; + int lineLength = 0; + for( ; d < len2; d+=3, e+=4 ) + { + encode3to4( source, d+off, 3, outBuff, e ); + + lineLength += 4; + if( breakLines && lineLength == MAX_LINE_LENGTH ) + { + outBuff[e+4] = NEW_LINE; + e++; + lineLength = 0; + } // end if: end of line + } // en dfor: each piece of array + + if( d < len ) + { + encode3to4( source, d+off, len - d, outBuff, e ); + e += 4; + } // end if: some padding needed + + return new String( outBuff, 0, e ); + } // end encodeBytes + + + /** + * Encodes a string in Base64 notation with line breaks + * after every 75 Base64 characters. + * + * @param s the string to encode + * @return the encoded string + * @since 1.3 + */ + public static String encodeString( String s ) + { + return encodeString( s, true ); + } // end encodeString + + /** + * Encodes a string in Base64 notation with line breaks + * after every 75 Base64 characters. + * + * @param s the string to encode + * @param breakLines Break lines at 80 characters or less. + * @return the encoded string + * @since 1.3 + */ + public static String encodeString( String s, boolean breakLines ) + { + return encodeBytes( s.getBytes(), breakLines ); + } // end encodeString + + + + +/* ******** D E C O D I N G M E T H O D S ******** */ + + + /** + * Decodes the first four bytes of array fourBytes + * and returns an array up to three bytes long with the + * decoded values. + * + * @param fourBytes the array with Base64 content + * @return array with decoded values + * @since 1.3 + */ + static byte[] decode4to3( byte[] fourBytes ) + { + byte[] outBuff1 = new byte[3]; + int count = decode4to3( fourBytes, 0, outBuff1, 0 ); + byte[] outBuff2 = new byte[ count ]; + + for( int i = 0; i < count; i++ ) + outBuff2[i] = outBuff1[i]; + + return outBuff2; + } + + + + + /** + * Decodes four bytes from array source + * and writes the resulting bytes (up to three of them) + * to destination. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * srcOffset and destOffset. + * This method does not check to make sure your arrays + * are large enough to accomodate srcOffset + 4 for + * the source array or destOffset + 3 for + * the destination array. + * This method returns the actual number of bytes that + * were converted from the Base64 encoding. + * + * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @return the number of decoded bytes converted + * @since 1.3 + */ + static int decode4to3( byte[] source, int srcOffset, byte[] destination, int destOffset ) + { + // Example: Dk== + if( source[ srcOffset + 2] == EQUALS_SIGN ) + { + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 ); + int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) + | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 ); + + destination[ destOffset ] = (byte)( outBuff >>> 16 ); + return 1; + } + + // Example: DkL= + else if( source[ srcOffset + 3 ] == EQUALS_SIGN ) + { + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ); + int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) + | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 ) + | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6 ); + + destination[ destOffset ] = (byte)( outBuff >>> 16 ); + destination[ destOffset + 1 ] = (byte)( outBuff >>> 8 ); + return 2; + } + + // Example: DkLE + else + { + try{ + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ) + // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 ); + int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) + | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 ) + | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6) + | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF ) ); + + + destination[ destOffset ] = (byte)( outBuff >> 16 ); + destination[ destOffset + 1 ] = (byte)( outBuff >> 8 ); + destination[ destOffset + 2 ] = (byte)( outBuff ); + + return 3; + }catch( Exception e){ + System.out.println(""+source[srcOffset]+ ": " + ( DECODABET[ source[ srcOffset ] ] ) ); + System.out.println(""+source[srcOffset+1]+ ": " + ( DECODABET[ source[ srcOffset + 1 ] ] ) ); + System.out.println(""+source[srcOffset+2]+ ": " + ( DECODABET[ source[ srcOffset + 2 ] ] ) ); + System.out.println(""+source[srcOffset+3]+ ": " + ( DECODABET[ source[ srcOffset + 3 ] ] ) ); + return -1; + } //e nd catch + } + } // end decodeToBytes + + + + /** + * Decodes data from Base64 notation. + * + * @param s the string to decode + * @return the decoded data + * @since 1.4 + */ + public static byte[] decode( String s ) + { + byte[] bytes = s.getBytes(); + return decode( bytes, 0, bytes.length ); + } // end decode + + + /** + * Decodes data from Base64 notation and + * returns it as a string. + * Equivlaent to calling + * new String( decode( s ) ) + * + * @param s the strind to decode + * @return The data as a string + * @since 1.4 + */ + public static String decodeToString( String s ) + { return new String( decode( s ) ); + } // end decodeToString + + + /** + * Attempts to decode Base64 data and deserialize a Java + * Object within. Returns null if there was an error. + * + * @param encodedObject The Base64 data to decode + * @return The decoded and deserialized object + * @since 1.4 + */ + public static Object decodeToObject( String encodedObject ) + { + byte[] objBytes = decode( encodedObject ); + + java.io.ByteArrayInputStream bais = null; + java.io.ObjectInputStream ois = null; + + try + { + bais = new java.io.ByteArrayInputStream( objBytes ); + ois = new java.io.ObjectInputStream( bais ); + + return ois.readObject(); + } // end try + catch( java.io.IOException e ) + { + e.printStackTrace(); + return null; + } // end catch + catch( java.lang.ClassNotFoundException e ) + { + e.printStackTrace(); + return null; + } // end catch + finally + { + try{ bais.close(); } catch( Exception e ){} + try{ ois.close(); } catch( Exception e ){} + } // end finally + } // end decodeObject + + + /** + * Decodes Base64 content in byte array format and returns + * the decoded byte array. + * + * @param source The Base64 encoded data + * @param off The offset of where to begin decoding + * @param len The length of characters to decode + * @return decoded data + * @since 1.3 + */ + public static byte[] decode( byte[] source, int off, int len ) + { + int len34 = len * 3 / 4; + byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output + int outBuffPosn = 0; + + byte[] b4 = new byte[4]; + int b4Posn = 0; + int i = 0; + byte sbiCrop = 0; + byte sbiDecode = 0; + len += off; + for( i = off; i < len; i++ ) + { + sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits + sbiDecode = DECODABET[ sbiCrop ]; + + if( sbiDecode >= WHITE_SPACE_ENC ) // White space, Equals sign or better + { + if( sbiDecode >= EQUALS_SIGN_ENC ) + { + b4[ b4Posn++ ] = sbiCrop; + if( b4Posn > 3 ) + { + outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn ); + b4Posn = 0; + + // If that was the equals sign, break out of 'for' loop + if( sbiCrop == EQUALS_SIGN ) + break; + } // end if: quartet built + + } // end if: equals sign or better + + } // end if: white space, equals sign or better + else + { + System.err.println( "Bad Base64 input character at " + i + ": " + source[i] + "(decimal)" ); + return null; + } // end else: + } // each input character + + byte[] out = new byte[ outBuffPosn ]; + System.arraycopy( outBuff, 0, out, 0, outBuffPosn ); + return out; + } // end decode + + + + + /* ******** I N N E R C L A S S I N P U T S T R E A M ******** */ + + + + /** + * A {@link Base64#InputStream} will read data from another + * {@link java.io.InputStream}, given in the constructor, + * and encode/decode to/from Base64 notation on the fly. + * + * @see Base64 + * @see java.io.FilterInputStream + * @since 1.3 + */ + public static class InputStream extends java.io.FilterInputStream + { + private boolean encode; // Encoding or decoding + private int position; // Current position in the buffer + private byte[] buffer; // Small buffer holding converted data + private int bufferLength; // Length of buffer (3 or 4) + private int numSigBytes; // Number of meaningful bytes in the buffer + private int lineLength; + private boolean breakLines; // Break lines at less than 80 characters + + + /** + * Constructs a {@link Base64#InputStream} in DECODE mode. + * + * @param in the {@link java.io.InputStream} from which to read data. + * @since 1.3 + */ + public InputStream( java.io.InputStream in ) + { + this( in, Base64.DECODE ); + } // end constructor + + + /** + * Constructs a {@link Base64#InputStream} in + * either ENCODE or DECODE mode. + * + * @param in the {@link java.io.InputStream} from which to read data. + * @param encode Conversion direction + * @see Base64#ENCODE + * @see Base64#DECODE + * @since 1.3 + */ + public InputStream( java.io.InputStream in, boolean encode ) + { + this( in, encode, true ); + } // end constructor + + + /** + * Constructs a {@link Base64#InputStream} in + * either ENCODE or DECODE mode. + * + * @param in the {@link java.io.InputStream} from which to read data. + * @param encode Conversion direction + * @param breakLines Break lines at less than 80 characters. + * @see Base64#ENCODE + * @see Base64#DECODE + * @since 1.3 + */ + public InputStream( java.io.InputStream in, boolean encode, boolean breakLines ) + { + super( in ); + this.breakLines = breakLines; + this.encode = encode; + this.bufferLength = encode ? 4 : 3; + this.buffer = new byte[ bufferLength ]; + this.position = -1; + this.lineLength = 0; + } // end constructor + + /** + * Reads enough of the input stream to convert + * to/from Base64 and returns the next byte. + * + * @return next byte + * @since 1.3 + */ + public int read() throws java.io.IOException + { + // Do we need to get data? + if( position < 0 ) + { + if( encode ) + { + byte[] b3 = new byte[3]; + int numBinaryBytes = 0; + for( int i = 0; i < 3; i++ ) + { + try + { + int b = in.read(); + + // If end of stream, b is -1. + if( b >= 0 ) + { + b3[i] = (byte)b; + numBinaryBytes++; + } // end if: not end of stream + + } // end try: read + catch( java.io.IOException e ) + { + // Only a problem if we got no data at all. + if( i == 0 ) + throw e; + + } // end catch + } // end for: each needed input byte + + if( numBinaryBytes > 0 ) + { + encode3to4( b3, 0, numBinaryBytes, buffer, 0 ); + position = 0; + numSigBytes = 4; + } // end if: got data + else + { + return -1; + } // end else + } // end if: encoding + + // Else decoding + else + { + byte[] b4 = new byte[4]; + int i = 0; + for( i = 0; i < 4; i++ ) + { + // Read four "meaningful" bytes: + int b = 0; + do{ b = in.read(); } + while( b >= 0 && DECODABET[ b & 0x7f ] <= WHITE_SPACE_ENC ); + + if( b < 0 ) + break; // Reads a -1 if end of stream + + b4[i] = (byte)b; + } // end for: each needed input byte + + if( i == 4 ) + { + numSigBytes = decode4to3( b4, 0, buffer, 0 ); + position = 0; + } // end if: got four characters + else if( i == 0 ){ + return -1; + } // end else if: also padded correctly + else + { + // Must have broken out from above. + throw new java.io.IOException( "Improperly padded Base64 input." ); + } // end + + } // end else: decode + } // end else: get data + + // Got data? + if( position >= 0 ) + { + // End of relevant data? + if( /*!encode &&*/ position >= numSigBytes ) + return -1; + + if( encode && breakLines && lineLength >= MAX_LINE_LENGTH ) + { + lineLength = 0; + return '\n'; + } // end if + else + { + lineLength++; // This isn't important when decoding + // but throwing an extra "if" seems + // just as wasteful. + + int b = buffer[ position++ ]; + + if( position >= bufferLength ) + position = -1; + + return b & 0xFF; // This is how you "cast" a byte that's + // intended to be unsigned. + } // end else + } // end if: position >= 0 + + // Else error + else + { + // When JDK1.4 is more accepted, use an assertion here. + throw new java.io.IOException( "Error in Base64 code reading stream." ); + } // end else + } // end read + + + /** + * Calls {@link #read} repeatedly until the end of stream + * is reached or len bytes are read. + * Returns number of bytes read into array or -1 if + * end of stream is encountered. + * + * @param dest array to hold values + * @param off offset for array + * @param len max number of bytes to read into array + * @return bytes read into array or -1 if end of stream is encountered. + * @since 1.3 + */ + public int read( byte[] dest, int off, int len ) throws java.io.IOException + { + int i; + int b; + for( i = 0; i < len; i++ ) + { + b = read(); + + //if( b < 0 && i == 0 ) + // return -1; + + if( b >= 0 ) + dest[off + i] = (byte)b; + else if( i == 0 ) + return -1; + else + break; // Out of 'for' loop + } // end for: each byte read + return i; + } // end read + + } // end inner class InputStream + + + + + + + /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */ + + + + /** + * A {@link Base64#OutputStream} will write data to another + * {@link java.io.OutputStream}, given in the constructor, + * and encode/decode to/from Base64 notation on the fly. + * + * @see Base64 + * @see java.io.FilterOutputStream + * @since 1.3 + */ + public static class OutputStream extends java.io.FilterOutputStream + { + private boolean encode; + private int position; + private byte[] buffer; + private int bufferLength; + private int lineLength; + private boolean breakLines; + + + /** + * Constructs a {@link Base64#OutputStream} in ENCODE mode. + * + * @param out the {@link java.io.OutputStream} to which data will be written. + * @since 1.3 + */ + public OutputStream( java.io.OutputStream out ) + { + this( out, Base64.ENCODE ); + } // end constructor + + + /** + * Constructs a {@link Base64#OutputStream} in + * either ENCODE or DECODE mode. + * + * @param out the {@link java.io.OutputStream} to which data will be written. + * @param encode Conversion direction + * @see Base64#ENCODE + * @see Base64#DECODE + * @since 1.3 + */ + public OutputStream( java.io.OutputStream out, boolean encode ) + { + this( out, encode, true ); + } // end constructor + + + /** + * Constructs a {@link Base64#OutputStream} in + * either ENCODE or DECODE mode. + * + * @param out the {@link java.io.OutputStream} to which data will be written. + * @param encode Conversion direction + * @param breakLines Break lines to be less than 80 characters. + * @see Base64#ENCODE + * @see Base64#DECODE + * @since 1.3 + */ + public OutputStream( java.io.OutputStream out, boolean encode, boolean breakLines ) + { + super( out ); + this.breakLines = breakLines; + this.encode = encode; + this.bufferLength = encode ? 3 : 4; + this.buffer = new byte[ bufferLength ]; + this.position = 0; + this.lineLength = 0; + } // end constructor + + + /** + * Writes the byte to the output stream after + * converting to/from Base64 notation. + * When encoding, bytes are buffered three + * at a time before the output stream actually + * gets a write() call. + * When decoding, bytes are buffered four + * at a time. + * + * @param theByte the byte to write + * @since 1.3 + */ + public void write(int theByte) throws java.io.IOException + { + if( encode ) + { + buffer[ position++ ] = (byte)theByte; + if( position >= bufferLength ) // Enough to encode. + { + out.write( Base64.encode3to4( buffer, bufferLength ) ); + + lineLength += 4; + if( breakLines && lineLength >= MAX_LINE_LENGTH ) + { + out.write( NEW_LINE ); + lineLength = 0; + } // end if: end of line + + position = 0; + } // end if: enough to output + } // end if: encoding + + // Else, Decoding + else + { + // Meaningful Base64 character? + if( DECODABET[ theByte & 0x7f ] > WHITE_SPACE_ENC ) + { + buffer[ position++ ] = (byte)theByte; + if( position >= bufferLength ) // Enough to output. + { + out.write( Base64.decode4to3( buffer ) ); + position = 0; + } // end if: enough to output + } // end if: meaningful base64 character + else if( DECODABET[ theByte & 0x7f ] != WHITE_SPACE_ENC ) + { + throw new java.io.IOException( "Invalid character in Base64 data." ); + } // end else: not white space either + } // end else: decoding + } // end write + + + + /** + * Calls {@link #write} repeatedly until len + * bytes are written. + * + * @param theBytes array from which to read bytes + * @param off offset for array + * @param len max number of bytes to read into array + * @since 1.3 + */ + public void write( byte[] theBytes, int off, int len ) throws java.io.IOException + { + for( int i = 0; i < len; i++ ) + { + write( theBytes[ off + i ] ); + } // end for: each byte written + + } // end write + + + /** + * Appropriately pads Base64 notation when encoding + * or throws an exception if Base64 input is not + * properly padded when decoding. + * + * @since 1.3 + */ + public void flush() throws java.io.IOException + { + super.flush(); + + if( position > 0 ) + { + if( encode ) + { + out.write( Base64.encode3to4( buffer, position ) ); + position = 0; + } // end if: encoding + else + { + throw new java.io.IOException( "Base64 input not properly padded." ); + } // end else: decoding + } // end if: buffer partially full + + out.flush(); + } // end flush + + + /** + * Flushes and closes (I think, in the superclass) the stream. + * + * @since 1.3 + */ + public void close() throws java.io.IOException + { + super.close(); + //this.flush(); + + out.close(); + + buffer = null; + out = null; + } // end close + + } // end inner class OutputStream + + +} // end class Base64 -- cgit v1.2.3