001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.commons.configuration;
019    
020    import static org.junit.Assert.assertEquals;
021    import static org.junit.Assert.assertFalse;
022    import static org.junit.Assert.assertNotNull;
023    import static org.junit.Assert.assertNull;
024    import static org.junit.Assert.assertTrue;
025    
026    import java.util.Hashtable;
027    import java.util.Properties;
028    
029    import javax.naming.Context;
030    import javax.naming.InitialContext;
031    import javax.naming.NameNotFoundException;
032    import javax.naming.NamingException;
033    
034    import org.junit.After;
035    import org.junit.Before;
036    import org.junit.Test;
037    
038    /**
039     * Test to see if the JNDIConfiguration works properly.
040     *
041     * @version $Id: TestJNDIConfiguration.java 1301996 2012-03-17 20:30:39Z sebb $
042     */
043    public class TestJNDIConfiguration {
044    
045        public static final String CONTEXT_FACTORY = MockInitialContextFactory.class.getName();
046    
047        private PotentialErrorJNDIConfiguration conf;
048        private NonStringTestHolder nonStringTestHolder;
049    
050        /** A test error listener for counting internal errors.*/
051        private ConfigurationErrorListenerImpl listener;
052    
053        @Before
054        public void setUp() throws Exception {
055    
056            System.setProperty("java.naming.factory.initial", CONTEXT_FACTORY);
057    
058            Properties props = new Properties();
059            props.put("java.naming.factory.initial", CONTEXT_FACTORY);
060            Context ctx = new InitialContext(props);
061            conf = new PotentialErrorJNDIConfiguration(ctx);
062    
063            nonStringTestHolder = new NonStringTestHolder();
064            nonStringTestHolder.setConfiguration(conf);
065    
066            listener = new ConfigurationErrorListenerImpl();
067            conf.addErrorListener(listener);
068        }
069    
070        /**
071         * Clears the test environment. If an error listener is defined, checks
072         * whether no error event was received.
073         */
074        @After
075        public void tearDown() throws Exception
076        {
077            if (listener != null)
078            {
079                listener.verify();
080            }
081        }
082    
083        @Test
084        public void testBoolean() throws Exception {
085            nonStringTestHolder.testBoolean();
086        }
087    
088        @Test
089        public void testBooleanDefaultValue() throws Exception {
090            nonStringTestHolder.testBooleanDefaultValue();
091        }
092    
093        @Test
094        public void testByte() throws Exception {
095            nonStringTestHolder.testByte();
096        }
097    
098        @Test
099        public void testDouble() throws Exception {
100            nonStringTestHolder.testDouble();
101        }
102    
103        @Test
104        public void testDoubleDefaultValue() throws Exception {
105            nonStringTestHolder.testDoubleDefaultValue();
106        }
107    
108        @Test
109        public void testFloat() throws Exception {
110            nonStringTestHolder.testFloat();
111        }
112    
113        @Test
114        public void testFloatDefaultValue() throws Exception {
115            nonStringTestHolder.testFloatDefaultValue();
116        }
117    
118        @Test
119        public void testInteger() throws Exception {
120            nonStringTestHolder.testInteger();
121        }
122    
123        @Test
124        public void testIntegerDefaultValue() throws Exception {
125            nonStringTestHolder.testIntegerDefaultValue();
126        }
127    
128        @Test
129        public void testLong() throws Exception {
130            nonStringTestHolder.testLong();
131        }
132    
133        @Test
134        public void testLongDefaultValue() throws Exception {
135            nonStringTestHolder.testLongDefaultValue();
136        }
137    
138        @Test
139        public void testShort() throws Exception {
140            nonStringTestHolder.testShort();
141        }
142    
143        @Test
144        public void testShortDefaultValue() throws Exception {
145            nonStringTestHolder.testShortDefaultValue();
146        }
147    
148        @Test
149        public void testListMissing() throws Exception {
150            nonStringTestHolder.testListMissing();
151        }
152    
153        @Test
154        public void testSubset() throws Exception {
155            nonStringTestHolder.testSubset();
156        }
157    
158        @Test
159        public void testProperties() throws Exception {
160            Object o = conf.getProperty("test.boolean");
161            assertNotNull(o);
162            assertEquals("true", o.toString());
163        }
164    
165        @Test
166        public void testContainsKey()
167        {
168            String key = "test.boolean";
169            assertTrue("'" + key + "' not found", conf.containsKey(key));
170    
171            conf.clearProperty(key);
172            assertFalse("'" + key + "' still found", conf.containsKey(key));
173        }
174    
175        @Test
176        public void testChangePrefix()
177        {
178            assertEquals("'test.boolean' property", "true", conf.getString("test.boolean"));
179            assertEquals("'boolean' property", null, conf.getString("boolean"));
180    
181            // change the prefix
182            conf.setPrefix("test");
183            assertEquals("'test.boolean' property", null, conf.getString("test.boolean"));
184            assertEquals("'boolean' property", "true", conf.getString("boolean"));
185        }
186    
187        @Test
188        public void testResetRemovedProperties() throws Exception
189        {
190            assertEquals("'test.boolean' property", "true", conf.getString("test.boolean"));
191    
192            // remove the property
193            conf.clearProperty("test.boolean");
194            assertEquals("'test.boolean' property", null, conf.getString("test.boolean"));
195    
196            // change the context
197            conf.setContext(new InitialContext());
198    
199            // get the property
200            assertEquals("'test.boolean' property", "true", conf.getString("test.boolean"));
201        }
202    
203        @Test
204        public void testConstructor() throws Exception
205        {
206            // test the constructor accepting a context
207            JNDIConfiguration c = new JNDIConfiguration(new InitialContext());
208    
209            assertEquals("'test.boolean' property", "true", c.getString("test.boolean"));
210    
211            // test the constructor accepting a context and a prefix
212            c = new JNDIConfiguration(new InitialContext(), "test");
213    
214            assertEquals("'boolean' property", "true", c.getString("boolean"));
215        }
216    
217        /**
218         * Configures the test config to throw an exception.
219         */
220        private PotentialErrorJNDIConfiguration setUpErrorConfig()
221        {
222            conf.installException();
223            conf.removeErrorListener(conf.getErrorListeners().iterator().next());
224            return conf;
225        }
226    
227        /**
228         * Tests whether the expected error events have been received.
229         *
230         * @param type the expected event type
231         * @param propName the name of the property
232         * @param propValue the property value
233         */
234        private void checkErrorListener(int type, String propName, Object propValue)
235        {
236            listener.verify(type, propName, propValue);
237            assertTrue("Wrong exception class",
238                    listener.getLastEvent().getCause() instanceof NamingException);
239            listener = null;
240        }
241    
242        /**
243         * Tests whether a JNDI configuration registers an error log listener.
244         */
245        @Test
246        public void testLogListener() throws NamingException
247        {
248            JNDIConfiguration c = new JNDIConfiguration();
249            assertEquals("No error log listener registered", 1, c
250                    .getErrorListeners().size());
251        }
252    
253        /**
254         * Tests handling of errors in getKeys().
255         */
256        @Test
257        public void testGetKeysError()
258        {
259            assertFalse("Iteration not empty", setUpErrorConfig().getKeys()
260                    .hasNext());
261            checkErrorListener(AbstractConfiguration.EVENT_READ_PROPERTY, null,
262                    null);
263        }
264    
265        /**
266         * Tests handling of errors in isEmpty().
267         */
268        @Test
269        public void testIsEmptyError() throws Exception
270        {
271            assertTrue("Error config not empty", setUpErrorConfig().isEmpty());
272            checkErrorListener(AbstractConfiguration.EVENT_READ_PROPERTY, null,
273                    null);
274        }
275    
276        /**
277         * Tests handling of errors in the containsKey() method.
278         */
279        @Test
280        public void testContainsKeyError()
281        {
282            assertFalse("Key contained after error", setUpErrorConfig()
283                    .containsKey("key"));
284            checkErrorListener(AbstractConfiguration.EVENT_READ_PROPERTY, "key",
285                    null);
286        }
287    
288        /**
289         * Tests handling of errors in getProperty().
290         */
291        @Test
292        public void testGetPropertyError()
293        {
294            assertNull("Wrong property value after error", setUpErrorConfig()
295                    .getProperty("key"));
296            checkErrorListener(AbstractConfiguration.EVENT_READ_PROPERTY, "key",
297                    null);
298        }
299    
300        /**
301         * Tests the getKeys() method when there are cycles in the tree.
302         */
303        @Test
304        public void testGetKeysWithCycles() throws NamingException
305        {
306            Hashtable<Object, Object> env = new Hashtable<Object, Object>();
307            env.put(MockInitialContextFactory.PROP_CYCLES, Boolean.TRUE);
308            InitialContext initCtx = new InitialContext(env);
309            JNDIConfiguration c = new JNDIConfiguration(initCtx);
310            c.getKeys("cycle");
311        }
312    
313        /**
314         * Tests getKeys() if no data is found. This should not cause a problem and
315         * not notify the error listeners.
316         */
317        @Test
318        public void testGetKeysNoData()
319        {
320            conf.installException(new NameNotFoundException("Test exception"));
321            assertFalse("Got keys", conf.getKeys().hasNext());
322            listener.verify();
323        }
324    
325        /**
326         * A special JNDI configuration implementation that can be configured to
327         * throw an exception when accessing the base context. Used for testing the
328         * exception handling.
329         */
330        public static class PotentialErrorJNDIConfiguration extends
331                JNDIConfiguration
332        {
333            /** An exception to be thrown by getBaseContext(). */
334            private NamingException exception;
335    
336            public PotentialErrorJNDIConfiguration(Context ctx)
337                    throws NamingException
338            {
339                super(ctx);
340            }
341    
342            /**
343             * Prepares this object to throw an exception when the JNDI context is
344             * queried.
345             *
346             * @param nex the exception to be thrown
347             */
348            public void installException(NamingException nex)
349            {
350                exception = nex;
351            }
352    
353            /**
354             * Prepares this object to throw a standard exception when the JNDI
355             * context is queried.
356             */
357            public void installException()
358            {
359                installException(new NamingException("Simulated JNDI exception!"));
360            }
361    
362            /**
363             * Returns the JNDI context. Optionally throws an exception.
364             */
365            @Override
366            public Context getBaseContext() throws NamingException
367            {
368                if (exception != null)
369                {
370                    throw exception;
371                }
372                return super.getBaseContext();
373            }
374        }
375    }