001    package org.apache.commons.digester3.plugins.strategies;
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 static org.apache.commons.digester3.binder.DigesterLoader.newLoader;
023    
024    import java.io.ByteArrayInputStream;
025    import java.io.ByteArrayOutputStream;
026    import java.io.IOException;
027    import java.io.InputStream;
028    
029    import org.apache.commons.digester3.Digester;
030    import org.apache.commons.digester3.plugins.PluginException;
031    import org.apache.commons.digester3.plugins.RuleLoader;
032    import org.apache.commons.digester3.xmlrules.FromXmlRulesModule;
033    import org.apache.commons.logging.Log;
034    import org.xml.sax.InputSource;
035    
036    /**
037     * A rule-finding algorithm which loads an xmlplugins-format file.
038     * <p>
039     * Note that the "include" feature of xmlrules is not supported.
040     * 
041     * @since 1.6
042     */
043    public class LoaderFromStream
044        extends RuleLoader
045    {
046    
047        private final byte[] input;
048    
049        /**
050         * The contents of the input stream are loaded into memory, and cached for later use.
051         * <p>
052         * The caller is responsible for closing the input stream after this method has returned.
053         *
054         * @param s the input stream has to be loaded into memory
055         * @throws Exception if any error occurs while reading the input stream
056         */
057        public LoaderFromStream( InputStream s )
058            throws Exception
059        {
060            try
061            {
062                ByteArrayOutputStream baos = new ByteArrayOutputStream();
063                byte[] buf = new byte[256];
064                for ( ;; )
065                {
066                    int i = s.read( buf );
067                    if ( i == -1 )
068                    {
069                        break;
070                    }
071                    baos.write( buf, 0, i );
072                }
073                input = baos.toByteArray();
074            }
075            finally
076            {
077                try
078                {
079                    if ( s != null )
080                    {
081                        s.close();
082                    }
083                }
084                catch ( IOException e )
085                {
086                    // close quietly
087                }
088            }
089        }
090    
091        /**
092         * {@inheritDoc}
093         */
094        @Override
095        public void addRules( final Digester d, final String path )
096            throws PluginException
097        {
098            Log log = d.getLogger();
099            boolean debug = log.isDebugEnabled();
100            if ( debug )
101            {
102                log.debug( "LoaderFromStream: loading rules for plugin at path [" + path + "]" );
103            }
104    
105            // Note that this input-source doesn't have any idea of its
106            // system id, so it has no way of resolving relative URLs
107            // such as the "include" feature of xmlrules. This is ok,
108            // because that doesn't work well with our approach of
109            // caching the input data in memory anyway.
110    
111            final InputSource source = new InputSource( new ByteArrayInputStream( input ) );
112            newLoader( new FromXmlRulesModule()
113            {
114    
115                @Override
116                protected void loadRules()
117                {
118                    useRootPath( path );
119                    loadXMLRules( source );
120                }
121    
122            } ).createRuleSet().addRuleInstances( d );
123        }
124    
125    }