001package org.andromda.cartridges.meta.metafacades;
002
003import java.util.ArrayList;
004import java.util.Collection;
005import java.util.Iterator;
006import java.util.List;
007
008/**
009 * @author <a href="http://www.mbohlen.de">Matthias Bohlen </a>
010 * @author Chad Brandon
011 * @author Cyril Combe
012 * @since 10.12.2003
013 */
014public class MethodData implements Comparable
015{
016    private String metafacadeName;
017    private String visibility;
018    private boolean isAbstract;
019    private String name;
020    private String returnTypeName;
021    private String documentation;
022    private final List<ArgumentData> arguments = new ArrayList<ArgumentData>();
023    private final List<String> exceptions = new ArrayList<String>();
024
025    /**
026     * @param metafacadeNameIn
027     * @param visibilityIn
028     * @param isAbstractIn
029     * @param returnTypeNameIn
030     * @param nameIn
031     * @param documentationIn
032     */
033    public MethodData(
034        String metafacadeNameIn,
035        String visibilityIn,
036        boolean isAbstractIn,
037        String returnTypeNameIn,
038        String nameIn,
039        String documentationIn)
040    {
041        this.metafacadeName = metafacadeNameIn;
042        this.visibility = visibilityIn;
043        this.isAbstract = isAbstractIn;
044        this.name = nameIn;
045        this.returnTypeName = returnTypeNameIn;
046        this.documentation = documentationIn;
047    }
048
049    /**
050     * @param argument
051     */
052    public void addArgument(ArgumentData argument)
053    {
054        this.arguments.add(argument);
055    }
056
057    /**
058     * @return arguments
059     */
060    public Collection<ArgumentData> getArguments()
061    {
062        return this.arguments;
063    }
064
065    /**
066     * @param typeName
067     */
068    public void addException(String typeName)
069    {
070        this.exceptions.add(typeName);
071    }
072
073    /**
074     * @return exceptions
075     */
076    public Collection<String> getExceptions()
077    {
078        return this.exceptions;
079    }
080
081    /**
082     * Gets the metafacade name.
083     *
084     * @return the name of the metafacade
085     */
086    public String getMetafacadeName()
087    {
088        return this.metafacadeName;
089    }
090
091    /**
092     * Gets the name of the method.
093     *
094     * @return the name.
095     */
096    public String getName()
097    {
098        return this.name;
099    }
100
101    /**
102     * Gets the name of the return type for this method.
103     *
104     * @return the return type name.
105     */
106    public String getReturnTypeName()
107    {
108        return this.returnTypeName;
109    }
110
111    /**
112     * Builds a string representing a declaration for this method.
113     *
114     * @param suppressAbstractDeclaration
115     *            optionally suppress the "abstract" modifier
116     * @return String the declaration
117     */
118    public String buildMethodDeclaration(boolean suppressAbstractDeclaration)
119    {
120        String declaration = this.visibility + ' '
121                + ((this.isAbstract && !suppressAbstractDeclaration) ? "abstract " : "")
122                + ((this.returnTypeName != null) ? (this.returnTypeName + ' ') : "") + this.name + '(';
123
124        declaration += getTypedArgumentList();
125        /*for (final Iterator iterator = this.arguments.iterator(); iterator.hasNext();)
126        {
127            final ArgumentData argument = (ArgumentData)iterator.next();
128            declaration += (argument.getFullyQualifiedTypeName() + " " + argument.getName());
129            if (iterator.hasNext())
130            {
131                declaration += ", ";
132            }
133        }*/
134        declaration += ')';
135
136        if (!this.exceptions.isEmpty())
137        {
138            declaration += " throws ";
139            for (final Iterator<String> iterator = this.exceptions.iterator(); iterator.hasNext();)
140            {
141                String exception = iterator.next();
142                declaration += exception;
143                if (iterator.hasNext())
144                {
145                    declaration += ", ";
146                }
147            }
148        }
149
150        return declaration;
151    }
152
153    /**
154     * Builds a string representing a comma separated parameter type + name list.
155     *
156     * @return String the declaration
157     */
158    public String getTypedArgumentList()
159    {
160        return getTypedArgumentList(null);
161    }
162
163    /**
164     * Builds a string representing a comma separated parameter type + name list.
165     *
166     * @param modifier Optional modifier before each parameter
167     * @return String the declaration
168     */
169    public String getTypedArgumentList(String modifier)
170    {
171        String declaration = "";
172
173        for (final Iterator<ArgumentData> iterator = this.arguments.iterator(); iterator.hasNext();)
174        {
175            final ArgumentData argument = iterator.next();
176            if (modifier!=null)
177            {
178                declaration += modifier + ' ';
179            }
180            declaration += (argument.getFullyQualifiedTypeName() + ' ' + argument.getName());
181            if (iterator.hasNext())
182            {
183                declaration += ", ";
184            }
185        }
186        return declaration;
187    }
188
189    /**
190     * Builds a string representing a call to the method.
191     *
192     * @return String how a call would look like
193     */
194    public String buildMethodCall()
195    {
196        String call = getName() + '(';
197
198        for (final Iterator<ArgumentData> iterator = this.arguments.iterator(); iterator.hasNext();)
199        {
200            final ArgumentData argument = iterator.next();
201            call += argument.getName();
202            if (iterator.hasNext())
203            {
204                call += ", ";
205            }
206        }
207        call += ')';
208        return call;
209    }
210
211    /**
212     * Builds a signature which can be used as a key into a map. Consists of the methodName, number of arguments,
213     * return type, the name and the f.q. types of the arguments.
214     *
215     * @return String the key that identifies this method
216     */
217    public String buildCharacteristicKey()
218    {
219        String key = ((this.returnTypeName != null) ? (this.returnTypeName + ' ') : "") + this.name + '(';
220
221        for (final Iterator<ArgumentData> iterator = this.arguments.iterator(); iterator.hasNext();)
222        {
223            final ArgumentData argument = iterator.next();
224            key += argument.getFullyQualifiedTypeName();
225            if (iterator.hasNext())
226            {
227                key += ',';
228            }
229        }
230        key += ')';
231
232        return key;
233    }
234
235    /**
236     * Indicates whether or not this method is abstract.
237     *
238     * @return true/false
239     */
240    public boolean isAbstract()
241    {
242        return this.isAbstract;
243    }
244
245    /**
246     * Gets the visibility of this method.
247     *
248     * @return the visibility.
249     */
250    public String getVisibility()
251    {
252        return this.visibility;
253    }
254
255    /**
256     * Gets the documentation for this method.
257     *
258     * @return the documentation.
259     */
260    public String getDocumentation()
261    {
262        return this.documentation;
263    }
264
265    /**
266     * Tells if this method returns something.
267     *
268     * @return boolean
269     */
270    public boolean isReturnTypePresent()
271    {
272        return this.returnTypeName != null && !"void".equals(this.returnTypeName);
273    }
274
275    /**
276     * @see Comparable#compareTo(Object)
277     */
278    public int compareTo(final Object object)
279    {
280        MethodData other = (MethodData)object;
281        final int result = getMetafacadeName().compareTo(other.getMetafacadeName());
282
283        // Use the characteristic key in order to have a deterministic order, starting with method name and number of arguments
284        return (result != 0) ? result : (name + arguments.size() + ", " + buildCharacteristicKey())
285            .compareTo(other.getName() + other.getArguments().size() + ", " + other.buildCharacteristicKey());
286    }
287
288    /**
289     * @see Object#toString()
290     */
291    @Override
292    public String toString()
293    {
294        return this.buildMethodDeclaration(false);
295    }
296}