001package org.apache.commons.digester3.binder;
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
022import static org.apache.commons.digester3.binder.BinderClassLoader.createBinderClassLoader;
023import static org.junit.Assert.assertArrayEquals;
024import static org.junit.Assert.assertEquals;
025import static org.junit.Assert.assertFalse;
026import static org.junit.Assert.assertNotNull;
027import static org.junit.Assert.assertNotSame;
028import static org.junit.Assert.assertSame;
029
030import java.io.ByteArrayInputStream;
031import java.io.ByteArrayOutputStream;
032import java.io.FileNotFoundException;
033import java.io.IOException;
034import java.io.InputStream;
035import java.io.UnsupportedEncodingException;
036import java.net.MalformedURLException;
037import java.net.URL;
038import java.net.URLConnection;
039import java.net.URLStreamHandler;
040import java.net.URLStreamHandlerFactory;
041import java.util.HashMap;
042import java.util.Map;
043
044import org.junit.Test;
045
046/**
047 * DIGESTER-155
048 */
049public final class BinderClassLoaderTestCase
050{
051
052    private BinderClassLoader classLoader = createBinderClassLoader( new ExtendedClassLoader() );
053
054    @Test
055    public void loadBoolean()
056        throws Exception
057    {
058        typeFound( "boolean", boolean.class );
059    }
060
061    @Test
062    public void loadByte()
063        throws Exception
064    {
065        typeFound( "byte", byte.class );
066    }
067
068    @Test
069    public void loadShort()
070        throws Exception
071    {
072        typeFound( "short", short.class );
073    }
074
075    @Test
076    public void loadInt()
077        throws Exception
078    {
079        typeFound( "int", int.class );
080    }
081
082    @Test
083    public void loadChar()
084        throws Exception
085    {
086        typeFound( "char", char.class );
087    }
088
089    @Test
090    public void loadLong()
091        throws Exception
092    {
093        typeFound( "long", long.class );
094    }
095
096    @Test
097    public void loadFloat()
098        throws Exception
099    {
100        typeFound( "float", float.class );
101    }
102
103    @Test
104    public void loadDouble()
105        throws Exception
106    {
107        typeFound( "double", double.class );
108    }
109
110    private void typeFound( String name, Class<?> expected )
111        throws Exception
112    {
113        Class<?> actual = classLoader.loadClass( name );
114        assertSame( expected, actual );
115    }
116
117    @Test
118    public void testGetResource()
119    {
120        ClassLoader clToAdapt = new ClassLoader()
121        {
122
123            @Override
124            public URL getResource( String name )
125            {
126                if ( "xxx".equals( name ) )
127                {
128                    return super.getResource( "org/apache/commons/digester3/binder/BinderClassLoaderTestCase.class" );
129                }
130                return super.getResource( name );
131            }
132
133        };
134        ClassLoader binderCl = createBinderClassLoader( clToAdapt );
135        assertNotNull( binderCl.getResource( "xxx" ) );
136    }
137
138    @Test
139    public void testLoadClass()
140        throws Exception
141    {
142        Class<?> dummyClass1 = Dummy.class;
143        Class<?> dummyClass2 = classLoader.loadClass( dummyClass1.getName() );
144
145        assertEquals( dummyClass1.getName(), dummyClass2.getName() );
146        assertFalse( dummyClass2.getDeclaredConstructor().newInstance() instanceof Dummy );
147        assertNotSame( dummyClass1, dummyClass2 );
148        assertNotSame( dummyClass1.getClassLoader(), dummyClass2.getClassLoader() );
149        assertSame( classLoader.getAdaptedClassLoader(), dummyClass2.getClassLoader() );
150    }
151
152    @Test
153    public void testGetPrefixedResource()
154        throws Exception
155    {
156        URL resource = classLoader.getResource( "inmemory:dummyResource" );
157        assertNotNull( resource );
158        assertEquals( resource.getPath(), "dummyResource" );
159        InputStream input = resource.openStream();
160        try
161        {
162            byte[] bytes = toByteArray( input );
163            assertArrayEquals( bytes, IN_MEMORY_RESOURCES.get( "dummyResource" ) );
164        }
165        finally
166        {
167            input.close();
168        }
169    }
170
171    private static byte[] toByteArray( InputStream input )
172        throws IOException
173    {
174        ByteArrayOutputStream result = new ByteArrayOutputStream( 512 );
175        int n;
176        while ( ( n = input.read() ) != -1 )
177        {
178            result.write( n );
179        }
180        return result.toByteArray();
181    }
182
183    private static final Map<String, byte[]> IN_MEMORY_RESOURCES = new HashMap<String, byte[]>();
184
185    static
186    {
187        try
188        {
189            IN_MEMORY_RESOURCES.put( "dummyResource", "Resource data".getBytes( "UTF-8" ) );
190
191            // put bytes of Dummy class
192            String dummyClassName = Dummy.class.getName();
193            String resourceName = dummyClassName.replace( '.', '/' ) + ".class";
194            InputStream input = Dummy.class.getClassLoader().getResourceAsStream( resourceName );
195            try
196            {
197                IN_MEMORY_RESOURCES.put( resourceName, toByteArray( input ) );
198            }
199            finally
200            {
201                input.close();
202            }
203        }
204        catch ( UnsupportedEncodingException e )
205        {
206            throw new ExceptionInInitializerError( e );
207        }
208        catch ( IOException e )
209        {
210            throw new ExceptionInInitializerError( e );
211        }
212    }
213
214    private static class ExtendedClassLoader
215        extends ClassLoader
216    {
217
218        private final InMemoryURLStreamHandlerFactory streamHandlerFactory = new InMemoryURLStreamHandlerFactory();
219
220        @Override
221        protected Class<?> loadClass( String name, boolean resolve )
222            throws ClassNotFoundException
223        {
224            String dummyClassName = Dummy.class.getName();
225            if ( dummyClassName.equals( name ) ) {
226                Class<?> result = findLoadedClass( name );
227                if ( result == null )
228                {
229                    byte[] byteCode = IN_MEMORY_RESOURCES.get( dummyClassName.replace( '.', '/' ) + ".class" );
230                    result = defineClass( name, byteCode, 0, byteCode.length );
231                    resolveClass( result );
232                }
233                return result;
234            }
235            return super.loadClass( name, resolve );
236        }
237
238        @Override
239        public URL getResource( String name )
240        {
241            if ( name.startsWith( "inmemory:" ) )
242            {
243                try
244                {
245                    return new URL( null, name, streamHandlerFactory.createURLStreamHandler( "inmemory" ) );
246                }
247                catch ( MalformedURLException e )
248                {
249                    throw new RuntimeException( e );
250                }
251            }
252            return super.getResource( name );
253        }
254
255        private static class InMemoryURLStreamHandlerFactory
256            implements URLStreamHandlerFactory
257        {
258            public URLStreamHandler createURLStreamHandler( String protocol )
259            {
260                return new URLStreamHandler()
261                {
262                    @Override
263                    protected URLConnection openConnection( URL u )
264                        throws IOException
265                    {
266                        return new URLConnection( u )
267                        {
268                            private InputStream inputStream;
269
270                            @Override
271                            public void connect()
272                                throws IOException
273                            {
274                                if ( !connected ) {
275                                    byte[] data = IN_MEMORY_RESOURCES.get( url.getPath() );
276                                    if ( data != null )
277                                    {
278                                        inputStream = new ByteArrayInputStream( data );
279                                    }
280                                    connected = true;
281                                }
282                            }
283
284                            @Override
285                            public InputStream getInputStream()
286                                throws IOException
287                            {
288                                connect();
289                                if ( inputStream == null )
290                                {
291                                    throw new FileNotFoundException( url.getPath() );
292                                }
293                                return inputStream;
294                            }
295                        };
296                    }
297                };
298            }
299        }
300    }
301
302    public static class Dummy
303    {
304    }
305
306}