001    /*
002     *   Copyright (C) Christian Schulte, 2005-206
003     *   All rights reserved.
004     *
005     *   Redistribution and use in source and binary forms, with or without
006     *   modification, are permitted provided that the following conditions
007     *   are met:
008     *
009     *     o Redistributions of source code must retain the above copyright
010     *       notice, this list of conditions and the following disclaimer.
011     *
012     *     o Redistributions in binary form must reproduce the above copyright
013     *       notice, this list of conditions and the following disclaimer in
014     *       the documentation and/or other materials provided with the
015     *       distribution.
016     *
017     *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
018     *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
019     *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
020     *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
021     *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
022     *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
023     *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
024     *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025     *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
026     *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027     *
028     *   $JOMC: KeyValueType.java 3956 2011-11-18 22:29:49Z schulte2005 $
029     *
030     */
031    package org.jomc.ant.types;
032    
033    import java.lang.reflect.InvocationTargetException;
034    import java.lang.reflect.Method;
035    import java.lang.reflect.Modifier;
036    import org.apache.commons.lang.builder.ToStringBuilder;
037    import org.apache.tools.ant.BuildException;
038    import org.apache.tools.ant.Location;
039    
040    /**
041     * Datatype holding a {@code key}, {@code value} and {@code type} property.
042     *
043     * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a>
044     * @version $JOMC: KeyValueType.java 3956 2011-11-18 22:29:49Z schulte2005 $
045     */
046    public class KeyValueType implements Cloneable
047    {
048    
049        /** The key of the type. */
050        private String key;
051    
052        /** The value of the type. */
053        private String value;
054    
055        /** The class of the type of {@code value}. */
056        private Class<?> type;
057    
058        /** Creates a new {@code KeyValueType} instance. */
059        public KeyValueType()
060        {
061            super();
062        }
063    
064        /**
065         * Gets the value of the {@code key} property.
066         *
067         * @return The value of the {@code key} property.
068         *
069         * @see #setKey(java.lang.String)
070         */
071        public final String getKey()
072        {
073            return this.key;
074        }
075    
076        /**
077         * Sets the value of the {@code key} property.
078         *
079         * @param k The new value of the {@code key} property.
080         *
081         * @see #getKey()
082         */
083        public final void setKey( final String k )
084        {
085            this.key = k;
086        }
087    
088        /**
089         * Gets the value of the {@code value} property.
090         *
091         * @return The value of the {@code value} property or {@code null}.
092         *
093         * @see #setValue(java.lang.String)
094         */
095        public final String getValue()
096        {
097            return this.value;
098        }
099    
100        /**
101         * Sets the value of the {@code value} property.
102         *
103         * @param v The new value of the {@code value} property or {@code null}.
104         *
105         * @see #getValue()
106         */
107        public final void setValue( final String v )
108        {
109            this.value = v;
110        }
111    
112        /**
113         * Gets the value of the {@code type} property.
114         *
115         * @return The value of the {@code type} property or {@code null}.
116         *
117         * @see #setType(java.lang.Class)
118         */
119        public final Class<?> getType()
120        {
121            return this.type;
122        }
123    
124        /**
125         * Sets the value of the {@code type} property.
126         *
127         * @param t The new value of the {@code type} property or {@code null}.
128         *
129         * @see #getType()
130         */
131        public final void setType( final Class<?> t )
132        {
133            this.type = t;
134        }
135    
136        /**
137         * Gets the object of the instance.
138         *
139         * @param location The location the object is requested at.
140         *
141         * @return The object of the instance or {@code null}.
142         *
143         * @throws NullPointerException if {@code location} is {@code null}.
144         * @throws BuildException if getting the object fails.
145         *
146         * @see #getType()
147         * @see #getValue()
148         */
149        public Object getObject( final Location location ) throws BuildException
150        {
151            if ( location == null )
152            {
153                throw new NullPointerException( "location" );
154            }
155    
156            try
157            {
158                Object o = this.getValue();
159    
160                if ( o != null )
161                {
162                    if ( this.getType() != null && !String.class.equals( this.getType() ) )
163                    {
164                        try
165                        {
166                            o = this.getType().getConstructor( String.class ).newInstance( o );
167                        }
168                        catch ( final NoSuchMethodException e )
169                        {
170                            final Method valueOf = this.getType().getMethod( "valueOf", String.class );
171    
172                            if ( Modifier.isStatic( valueOf.getModifiers() )
173                                 && valueOf.getReturnType().equals( this.getType() ) )
174                            {
175                                o = valueOf.invoke( null, o );
176                            }
177                            else
178                            {
179                                throw new BuildException(
180                                    Messages.getMessage( "noSuchMethodCreatingValueObject", this.getType(),
181                                                         this.getValue(), this.getType().getSimpleName() ), e, location );
182    
183                            }
184                        }
185                    }
186                }
187                else if ( this.getType() != null )
188                {
189                    o = this.getType().newInstance();
190                }
191    
192                return o;
193            }
194            catch ( final NoSuchMethodException e )
195            {
196                throw new BuildException(
197                    Messages.getMessage( "noSuchMethodCreatingValueObject", this.getType(),
198                                         this.getValue(), this.getType().getSimpleName() ), e, location );
199    
200            }
201            catch ( final InstantiationException e )
202            {
203                throw new BuildException( Messages.getMessage( "failureCreatingValueObject", this.getType(),
204                                                               this.getValue() ), e, location );
205    
206            }
207            catch ( final IllegalAccessException e )
208            {
209                throw new BuildException( Messages.getMessage( "failureCreatingValueObject", this.getType(),
210                                                               this.getValue() ), e, location );
211    
212            }
213            catch ( final InvocationTargetException e )
214            {
215                throw new BuildException( Messages.getMessage( "failureCreatingValueObject", this.getType(),
216                                                               this.getValue() ), e, location );
217    
218            }
219        }
220    
221        /**
222         * Creates and returns a copy of this object.
223         *
224         * @return A copy of this object.
225         */
226        @Override
227        public KeyValueType clone()
228        {
229            try
230            {
231                return (KeyValueType) super.clone();
232            }
233            catch ( final CloneNotSupportedException e )
234            {
235                throw new AssertionError( e );
236            }
237        }
238    
239        /**
240         * Creates and returns a string representation of the object.
241         *
242         * @return A string representation of the object.
243         */
244        @Override
245        public String toString()
246        {
247            return ToStringBuilder.reflectionToString( this );
248        }
249    
250    }