1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.configuration;
18  
19  import java.util.Hashtable;
20  
21  import javax.naming.Context;
22  import javax.naming.NameClassPair;
23  import javax.naming.NameNotFoundException;
24  import javax.naming.NamingEnumeration;
25  import javax.naming.NamingException;
26  import javax.naming.spi.InitialContextFactory;
27  
28  import com.mockobjects.dynamic.C;
29  import com.mockobjects.dynamic.Mock;
30  
31  /***
32   * A mock implementation of the <code>InitialContextFactory</code> interface.
33   * This implementation will return a mock context that contains some test data.
34   *
35   * @author <a
36   * href="http://jakarta.apache.org/commons/configuration/team-list.html">Commons
37   * Configuration team</a>
38   * @version $Id: MockInitialContextFactory.java 506128 2007-02-11 20:43:08Z oheger $
39   */
40  public class MockInitialContextFactory implements InitialContextFactory
41  {
42      /*** Constant for the lookup method. */
43      private static final String METHOD_LOOKUP = "lookup";
44  
45      /*** Constant for the list method. */
46      private static final String METHOD_LIST = "list";
47  
48      /*** Constant for the name of the missing property. */
49      private static final String MISSING_PROP = "/missing";
50  
51      /*** Constant for the name of the prefix. */
52      private static final String PREFIX = "test/";
53  
54      /*** An array with the names of the supported properties. */
55      private static final String[] PROP_NAMES =
56      { "key", "key2", "short", "boolean", "byte", "double", "float", "integer",
57              "long", "onlyinjndi" };
58  
59      /*** An array with the values of the supported properties. */
60      private static final String[] PROP_VALUES =
61      { "jndivalue", "jndivalue2", "1", "true", "10", "10.25", "20.25", "10",
62              "1000000", "true" };
63  
64      /*** An array with properties that are requested, but are not in the context. */
65      private static final String[] MISSING_NAMES =
66      { "missing/list", "test/imaginarykey", "foo/bar" };
67  
68      /***
69       * Creates a <code>Context</code> object that is backed by a mock object.
70       * The mock context can be queried for the values of certain test
71       * properties. It also supports listing the contained (sub) properties.
72       *
73       * @param env the environment
74       * @return the context mock
75       */
76      public Context getInitialContext(Hashtable env) throws NamingException
77      {
78          Mock mockTopCtx = createCtxMock(PREFIX);
79          Mock mockPrfxCtx = createCtxMock("");
80          Mock mockBaseCtx = new Mock(Context.class);
81          mockBaseCtx.matchAndReturn(METHOD_LOOKUP, C.eq(""), mockTopCtx.proxy());
82          mockBaseCtx.matchAndReturn(METHOD_LOOKUP, C.eq("test"), mockPrfxCtx
83                  .proxy());
84          mockTopCtx.matchAndReturn(METHOD_LOOKUP, C.eq("test"), mockPrfxCtx
85                  .proxy());
86          mockTopCtx.matchAndReturn(METHOD_LIST, C.eq(""), createEnumMock(
87                  mockTopCtx, new String[]
88                  { "test" }, new Object[]
89                  { mockPrfxCtx.proxy() }).proxy());
90          mockPrfxCtx.matchAndReturn(METHOD_LIST, C.eq(""), createEnumMock(
91                  mockPrfxCtx, PROP_NAMES, PROP_VALUES).proxy());
92          return (Context) mockBaseCtx.proxy();
93      }
94  
95      /***
96       * Creates a mock for a Context with the specified prefix.
97       *
98       * @param prefix the prefix
99       * @return the mock for the context
100      */
101     private Mock createCtxMock(String prefix)
102     {
103         Mock mockCtx = new Mock(Context.class);
104         for (int i = 0; i < PROP_NAMES.length; i++)
105         {
106             bind(mockCtx, prefix + PROP_NAMES[i], PROP_VALUES[i]);
107             String errProp = (prefix.length() > 0) ? PROP_NAMES[i] : PREFIX
108                     + PROP_NAMES[i];
109             bindError(mockCtx, errProp);
110         }
111         for (int i = 0; i < MISSING_NAMES.length; i++)
112         {
113             bindError(mockCtx, MISSING_NAMES[i]);
114         }
115         return mockCtx;
116     }
117 
118     /***
119      * Binds a property value to the mock context.
120      *
121      * @param mockCtx the context
122      * @param name the name of the property
123      * @param value the value of the property
124      */
125     private void bind(Mock mockCtx, String name, String value)
126     {
127         mockCtx.matchAndReturn(METHOD_LOOKUP, C.eq(name), value);
128         bindError(mockCtx, name + MISSING_PROP);
129     }
130 
131     /***
132      * Configures the mock to expect a call for a non existing property.
133      *
134      * @param mockCtx the mock
135      * @param name the name of the property
136      */
137     private void bindError(Mock mockCtx, String name)
138     {
139         mockCtx.matchAndThrow(METHOD_LOOKUP, C.eq(name),
140                 new NameNotFoundException("unknown property"));
141     }
142 
143     /***
144      * Creates and initializes a mock for a naming enumeration.
145      *
146      * @param mockCtx the mock representing the context
147      * @param names the names contained in the iteration
148      * @param values the corresponding values
149      * @return the mock for the enumeration
150      */
151     private Mock createEnumMock(Mock mockCtx, String[] names, Object[] values)
152     {
153         Mock mockEnum = new Mock(NamingEnumeration.class);
154         for (int i = 0; i < names.length; i++)
155         {
156             NameClassPair ncp = new NameClassPair(names[i], values[i]
157                     .getClass().getName());
158             mockEnum.expectAndReturn("hasMore", true);
159             mockEnum.expectAndReturn("next", ncp);
160         }
161         mockEnum.expectAndReturn("hasMore", false);
162         mockEnum.expect("close");
163         return mockEnum;
164     }
165 }