View Javadoc

1   ////////////////////////////////////////////////////////////////////////////////
2   // MillScript: an Open Spice interpreter and batch website creation tool
3   // Copyright (C) 2005 Kevin Rogers
4   //
5   // This file is part of MillScript.
6   //
7   // MillScript is free software; you can redistribute it and/or modify it under
8   // the terms of the GNU General Public License as published by the Free
9   // Software Foundation; either version 2 of the License, or (at your option)
10  // any later version.
11  //
12  // MillScript is distributed in the hope that it will be useful, but WITHOUT
13  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  // more details.
16  //
17  // You should have received a copy of the GNU General Public License along with
18  // MillScript; if not, write to the Free Software Foundation, Inc., 59 Temple
19  // Place, Suite 330, Boston, MA  02111-1307  USA
20  ////////////////////////////////////////////////////////////////////////////////
21  package org.millscript.millscript.conf.functions;
22  
23  import org.millscript.commons.alert.alerts.Fault;
24  import org.millscript.millscript.alert.Alerts;
25  import org.millscript.millscript.functions.Function;
26  import org.millscript.millscript.vm.Machine;
27  import org.millscript.millscript.vm.Package;
28  
29  import java.lang.reflect.Constructor;
30  import java.lang.reflect.InvocationTargetException;
31  
32  
33  /**
34   * This class implements the configuration function <code>AddFunction</code>.
35   */
36  public class AddFunctionFunction extends Function {
37  
38      /**
39       * The package we should add functions to.
40       */
41      private Package pack;
42  
43      /**
44       * Constructs a new add function function, to add a function to the given
45       * package.
46       *
47       * @param p the package we should add functions to
48       */
49      public AddFunctionFunction( final Package p ) {
50          this.pack = p;
51      }
52  
53      /**
54       * @see org.millscript.millscript.functions.Function#apply(org.millscript.millscript.vm.Machine, int)
55       */
56      @Override
57      @SuppressWarnings("unchecked")
58      public void apply( Machine mc, int nargs ) {
59          checkNargs( mc, 2, nargs );
60          final String functionClassName = mc.popString();
61          final String functionName = mc.popString();
62          try {
63              // Get the function Class object for the configuration entry
64              final Class< ? > functionClass = Class.forName( functionClassName );
65              // Check the retrieved class is an extension of a Function
66              if ( Function.class.isAssignableFrom( functionClass ) ) {
67                  // Return an instance of the function's class
68                  final Function function = this.constructFunction( (Class< Function >) functionClass );
69                  // Bind the function symbol to the Function object
70                  pack.bindConst( functionName, function );
71              } else {
72                  // Hmmm. Not a Function.
73                  throw new Fault(
74                      "A function must inherit from the Function class"
75                  ).culprit( "class", functionClass ).mishap();
76              }
77          } catch ( ClassNotFoundException ex ) {
78              throw(
79                  Alerts.parse(
80                      "Function Class not found",
81                      "Ensure function class is available in a classes folder"
82                  ).culprit( "class", functionClassName ).mishap()
83              );
84          }
85      }
86  
87      /**
88       * Returns a new instance of the specified function class.
89       *
90       * @param functionClass the <code>Function</code> class to make a new
91       * instance of.
92       * @return  a new instance of the specified <code>Function</code> class
93       */
94      public Function constructFunction( final Class< Function > functionClass ) {
95          try {
96              try {
97                  // Try to find a contructor that takes a package as its sole
98                  // parameter
99                  Constructor< Function > c = functionClass.getConstructor( Package.class );
100                 // Good, we're still here so we found it.
101                 return c.newInstance( this.pack );
102             } catch ( NoSuchMethodException ex ) {
103                 try {
104                     Constructor< Function > c = functionClass.getConstructor();
105                     // Good, we're still here so we found it.
106                     return c.newInstance();
107                 } catch ( NoSuchMethodException ex2 ) {
108                     throw new Fault(
109                         "Could not construct function - need an empty or single(Package) arg constructor"
110                     ).culprit( "class", functionClass ).setParentThrowable( ex2 ).mishap();
111                 }
112             }
113             
114         } catch ( ExceptionInInitializerError ex ) {
115             throw new Fault(
116                 "Could not construct function - unexpected failure in a static initialiser"
117             ).culprit( "class", functionClass ).setParentThrowable( ex ).mishap();
118         } catch ( IllegalAccessException ex ) {
119             throw new Fault(
120                 "Could not construct function - illegal access to constructor"
121             ).culprit( "class", functionClass ).setParentThrowable( ex ).mishap();
122         } catch ( IllegalArgumentException ex ) {
123             throw new Fault(
124                 "Could not construct function - illegal argument for constructor"
125             ).culprit( "class", functionClass ).setParentThrowable( ex ).mishap();
126         } catch ( InstantiationException ex ) {
127             throw new Fault(
128                 "Could not construct function - abstract class cannot be constructed"
129             ).culprit( "class", functionClass ).setParentThrowable( ex ).mishap();
130         } catch ( InvocationTargetException ex ) {
131             throw new Fault(
132                 "Could not construct function - constructor threw an exception"
133             ).culprit(
134                 "class",
135                 functionClass
136             ).culprit(
137                 "exception",
138                 ex.getCause()
139             ).setParentThrowable( ex ).mishap();
140         } catch ( SecurityException ex ) {
141             throw new Fault(
142                 "Could not construct function - access to constructor denied"
143             ).culprit( "class", functionClass ).setParentThrowable( ex ).mishap();
144         }
145     }
146 
147 }