001    package org.apache.fulcrum.yaafi.framework.crypto;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import org.apache.fulcrum.yaafi.framework.reflection.Clazz;
023    
024    import java.io.InputStream;
025    
026    /**
027     * Factory class to get a decrypting input stream for reading configuration
028     * files. The implementation uses dynamic class loading to make decryption
029     * an optional feature which is highly desirable when avoiding the ECCN
030     * export code problems.
031     *
032     * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl </a>
033     */
034    
035    public class CryptoStreamFactory
036    {
037        /** is the instance already initialized */
038        private static boolean isInitialized;
039    
040        /** the factory to create encrypting input streams */
041        private static Object cryptoStreamFactory;
042    
043        /** the name of the class to be loaded */
044        private static String className = "org.apache.fulcrum.jce.crypto.CryptoStreamFactoryImpl";
045    
046        /**
047         * Create a (potentially) decrypting input stream using the default
048         * password.
049         *
050         * @param is the input stream to be decrypted
051         * @param isEncrypted the encryption mode (true|false|auto)
052         * @return a decrypting input stream
053         * @throws Exception reading the input stream failed
054         */
055        public static InputStream getDecryptingInputStream( InputStream is, String isEncrypted )
056            throws Exception
057        {
058            InputStream result;
059            
060            if( isEncrypted.equalsIgnoreCase("true") )
061            {
062                // a decrypting input stream was requested
063                result = createDecryptingInputStream(is, "getInputStream");
064            }
065            else if( isEncrypted.equalsIgnoreCase("auto") && hasCryptoStreamFactory())
066            {
067                // no user-supplied preferences but crypto stream is available
068                result = createDecryptingInputStream(is, "getSmartInputStream");
069            }
070            else if( isEncrypted.equalsIgnoreCase("auto") && !hasCryptoStreamFactory())
071            {
072                // no user-supplied perferences so we fall back to normal input stream
073                result = is;
074            }
075            else if( isEncrypted.equalsIgnoreCase("false") )
076            {
077                // just use normal input stream
078                result = is;
079            }
080            else
081            {
082                throw new IllegalArgumentException("Unknown decryption mode : " + isEncrypted);
083            }
084    
085            return result;
086        }
087    
088        /**
089         * Factory method to create a decrypting input stream.
090         *
091         * @param is the input stream to be decrypted
092         * @param factoryMethodName the name of the factory method
093         * @return a decrypting input stream
094         * @throws Exception creating the decrypting input stream failed
095         */
096        private static InputStream createDecryptingInputStream( InputStream is, String factoryMethodName )
097            throws Exception
098        {
099            Class[] signature = {InputStream.class};
100            Object[] args = {is};
101            Object cryptoStreamFactory = getCryptoStreamFactory();
102    
103            if(cryptoStreamFactory == null)
104            {
105                throw new IllegalStateException("No CryptoStreamFactory available - unable to create a decrypting input stream");
106            }
107            else
108            {
109                return (InputStream) Clazz.invoke(cryptoStreamFactory, factoryMethodName, signature, args);
110            }
111        }
112    
113        /**
114         * Factory method to create a CryptoStreamFactory.
115         */
116        private synchronized static Object getCryptoStreamFactory()
117            throws Exception            
118        {
119            if(!isInitialized)
120            {
121                isInitialized = true;
122                ClassLoader clazzLoader = CryptoStreamFactory.class.getClassLoader();
123    
124                if(Clazz.hasClazz(clazzLoader, className))
125                {
126                    Class[] signature = {};
127                    Object[] args = {};
128                    Class clazz = Clazz.getClazz(clazzLoader, className);
129                    cryptoStreamFactory = Clazz.newInstance(clazz, signature, args);
130                }
131            }
132                        
133            return cryptoStreamFactory;
134        }
135    
136        /**
137         * @return true if a CryptoStreamFactory is available
138         */
139        private static boolean hasCryptoStreamFactory()
140            throws Exception
141        {
142            return ( getCryptoStreamFactory() != null );
143        }
144    }