001    /*
002     * Copyright 2006 Stephen J. McConnell.
003     *
004     * Licensed  under the  Apache License,  Version 2.0  (the "License");
005     * you may not use  this file  except in  compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *   http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed  under the  License is distributed on an "AS IS" BASIS,
012     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
013     * implied.
014     *
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package net.dpml.lang;
020    
021    import dpml.util.ElementHelper;
022    
023    import java.io.File;
024    import java.io.IOException;
025    import java.net.URI;
026    import java.net.URL;
027    
028    import net.dpml.transit.Artifact;
029    
030    import org.w3c.dom.Document;
031    import org.w3c.dom.Element;
032    import org.w3c.dom.NamedNodeMap;
033    import org.w3c.dom.Node;
034    
035    /**
036     * Exception related to data decoding from a DOM element.
037     */
038    public class DecodingException extends IOException
039    {
040        private final Element m_element;
041        
042       /**
043        * Create a new decoding exception.
044        * @param element the element representing the source of the error
045        * @param message the exception message
046        */
047        public DecodingException( String message, Element element )
048        {
049            this( message, null, element );
050        }
051        
052       /**
053        * Create a new decoding exception.
054        * @param element the element representing the source of the error
055        * @param message the exception message
056        * @param cause the causal exception
057        */
058        public DecodingException( String message, Throwable cause, Element element )
059        {
060            super( message );
061            if( null != cause )
062            {
063                super.initCause( cause );
064            }
065            m_element = element;
066        }
067        
068       /**
069        * Get the element that is the subject of this exception.
070        * @return the subject element
071        */
072        public Element getElement()
073        {
074            return m_element;
075        }
076        
077       /**
078        * Return a string representation of the exception.
079        * @return the string value
080        */
081        public String getMessage()
082        {
083            try
084            {
085                String message = super.getMessage();
086                StringBuffer buffer = new StringBuffer( message );
087                Element element = getElement();
088                if( null != element )
089                {
090                    Document document = element.getOwnerDocument();
091                    String uri = document.getDocumentURI();
092                    if( null != uri )
093                    {
094                        buffer.append( "\nSource: " + uri  );
095                        String filename = getSourceFilePath( uri );
096                        if( null != filename )
097                        {
098                            buffer.append( "\nFile: " + filename );
099                        }
100                        buffer.append( "\n" );
101                    }
102                    String listing = list( element );
103                    buffer.append( listing );
104                }
105                return buffer.toString();
106            }
107            catch( Throwable e )
108            {
109                return super.getMessage();
110            }
111        }
112        
113       /**
114        * Static utility operation that returns a string representation of a DOM element.
115        * @param element the element to stringify
116        * @return the string value
117        */
118        public static String list( Element element )
119        {
120            return list( element, "" );
121        }
122        
123       /**
124        * Static utility operation that returns a syring representation of a DOM element.
125        * @param element the element to stringify
126        * @param pad padding offset
127        * @return the string value
128        */
129        public static String list( Element element, String pad )
130        {
131            if( null == element )
132            {
133                return "";
134            }
135            StringBuffer buffer = new StringBuffer();
136            String tag = element.getTagName();
137            buffer.append( pad + "<" );
138            buffer.append( tag );
139            NamedNodeMap map = element.getAttributes();
140            for( int i=0; i<map.getLength(); i++ )
141            {
142                Node item = map.item( i );
143                buffer.append( " " + item.getNodeName() + "=\"" );
144                buffer.append( item.getNodeValue() );
145                buffer.append( "\"" );
146            }
147            
148            Element[] children = ElementHelper.getChildren( element );
149            if( children.length > 0 )
150            {
151                buffer.append( ">" );
152                for( int i=0; i<children.length; i++ )
153                {
154                    Element child = children[i];
155                    String listing = list( child, pad + "  " );
156                    String tagName = child.getTagName();
157                    buffer.append( "\n" + listing );
158                }
159                buffer.append( "\n" + pad + "</" + tag + ">" );
160            }
161            else
162            {
163                buffer.append( "/>" );
164            }
165            return buffer.toString();
166        }
167        
168        private static String getSourceFilePath( String value )
169        {
170            try
171            {
172                URI uri = URI.create( value );
173                if( Artifact.isRecognized( uri ) )
174                {
175                    URL url = Artifact.toURL( uri );
176                    File file = (File) url.getContent( new Class[]{File.class} );
177                    return file.getCanonicalPath();
178                }
179                return null;
180            }
181            catch( Throwable e )
182            {
183                return null;
184            }
185        }
186        
187    }