Adding a patched XML-Security initialization class. This allows for compatibility...
authorwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 10 Nov 2004 00:20:14 +0000 (00:20 +0000)
committerwassa <wassa@ab3bd59b-922f-494d-bb5f-6f0a3c29deca>
Wed, 10 Nov 2004 00:20:14 +0000 (00:20 +0000)
git-svn-id: https://subversion.switch.ch/svn/shibboleth/java-idp/trunk@1183 ab3bd59b-922f-494d-bb5f-6f0a3c29deca

src/org/apache/xml/security/Init.java [new file with mode: 0644]

diff --git a/src/org/apache/xml/security/Init.java b/src/org/apache/xml/security/Init.java
new file mode 100644 (file)
index 0000000..980719e
--- /dev/null
@@ -0,0 +1,697 @@
+/*
+ * Copyright  1999-2004 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.xml.security;
+
+
+
+import java.io.*;
+import java.lang.reflect.Method;
+import java.util.*;
+import javax.xml.parsers.*;
+import org.apache.xml.security.algorithms.JCEMapper;
+import org.apache.xml.security.algorithms.SignatureAlgorithm;
+import org.apache.xml.security.c14n.Canonicalizer;
+import org.apache.xml.security.exceptions.XMLSecurityException;
+import org.apache.xml.security.keys.ContentHandlerAlreadyRegisteredException;
+import org.apache.xml.security.keys.KeyInfo;
+import org.apache.xml.security.keys.keyresolver.KeyResolver;
+import org.apache.xml.security.transforms.Transform;
+import org.apache.xml.security.transforms.implementations.FuncHere;
+import org.apache.xml.security.utils.*;
+import org.apache.xml.security.utils.resolver.ResourceResolver;
+import org.apache.xpath.XPathAPI;
+import org.apache.xpath.compiler.FuncLoader;
+import org.apache.xpath.compiler.FunctionTable;
+import org.apache.xpath.functions.Function;
+import org.w3c.dom.*;
+
+
+/**
+ * This class does the configuration of the library. This includes creating
+ * the mapping of Canonicalization and Transform algorithms. Initialization is
+ * done by calling {@link Init#init} which should be done in any static block
+ * of the files of this library. We ensure that this call is only executed once.
+ *
+ * @author $Author$
+ */
+public class Init {
+
+  /** {@link org.apache.commons.logging} logging facility */
+  static org.apache.commons.logging.Log log = 
+        org.apache.commons.logging.LogFactory.getLog(Init.class.getName());
+
+   /** Field _initialized */
+   private static boolean _alreadyInitialized = false;
+
+   /**
+    * Method isInitialized
+    *
+    *
+    */
+   public static final boolean isInitialized() {
+      return Init._alreadyInitialized;
+   }
+
+   /**
+    * Method init
+    *
+    */
+   public synchronized static void init() {
+
+      if (!_alreadyInitialized) {
+         _alreadyInitialized = true;
+
+         try {
+            long XX_init_start = System.currentTimeMillis();
+            long XX_prng_start = System.currentTimeMillis();
+
+            PRNG.init(new java.security.SecureRandom());
+
+            long XX_prng_end = System.currentTimeMillis();
+
+            /* read library configuration file */
+            long XX_parsing_start = System.currentTimeMillis();
+            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+
+            dbf.setNamespaceAware(true);
+            dbf.setValidating(false);
+
+            DocumentBuilder db = dbf.newDocumentBuilder();
+            // InputStream is = Class.forName("org.apache.xml.security.Init").getResourceAsStream("resource/config.xml");
+            String cfile = System.getProperty("org.apache.xml.security.resource.config");
+            InputStream is =
+               Class.forName("org.apache.xml.security.Init")
+                  .getResourceAsStream(cfile != null ? cfile : "resource/config.xml");
+
+            Document doc = db.parse(is);
+            long XX_parsing_end = System.currentTimeMillis();
+            Element context = doc.createElementNS(null, "nscontext");
+
+            context.setAttributeNS(
+               Constants.NamespaceSpecNS, "xmlns:x",
+                    "http://www.xmlsecurity.org/NS/#configuration");
+            long XX_configure_i18n_start = System.currentTimeMillis();
+
+            {
+
+               /* configure internationalization */
+               Attr langAttr = (Attr) XPathAPI.selectSingleNode(
+                  doc,
+                  "/x:Configuration/x:ResourceBundles/@defaultLanguageCode",
+                  context);
+               Attr countryAttr = (Attr) XPathAPI.selectSingleNode(
+                  doc,
+                  "/x:Configuration/x:ResourceBundles/@defaultCountryCode",
+                  context);
+               String languageCode = (langAttr == null)
+                                     ? null
+                                     : langAttr.getNodeValue();
+               String countryCode = (countryAttr == null)
+                                    ? null
+                                    : countryAttr.getNodeValue();
+
+               I18n.init(languageCode, countryCode);
+            }
+
+            long XX_configure_i18n_end = System.currentTimeMillis();
+
+            /**
+             * Try to register our here() implementation as internal function.
+             */
+            long XX_configure_reg_here_start = System.currentTimeMillis();
+
+            {
+                FunctionTable.installFunction("here", new FuncHere());
+                log.debug("Registered class " + FuncHere.class.getName()
+                        + " for XPath function 'here()' function in internal table");
+
+                /* The following tweak by "Eric Olson" <ego@alum.mit.edu>
+                 * is to enable xml-security to play with JDK 1.4 which
+                 * unfortunately bundles an old version of Xalan
+                 */
+                FuncLoader funcHereLoader = new FuncHereLoader();
+
+                try {
+                    java.lang.reflect.Field mFunctions = FunctionTable.class.getField("m_functions");
+                    FuncLoader[] m_functions = (FuncLoader[]) mFunctions.get(null);
+
+                    for (int i = 0; i < m_functions.length; i++) {
+                        FuncLoader loader = m_functions[i];
+
+                        if (loader != null) {
+                            log.debug("Func " + i + " " + loader.getName());
+
+                            if (loader.getName().equals(funcHereLoader.getName())) {
+                                m_functions[i] = funcHereLoader;
+                            }
+                        }
+                    }
+                } catch (Exception e) {
+                    log.info("Unable to patch xalan function table.", e);
+                }
+            }
+             
+            long XX_configure_reg_here_end = System.currentTimeMillis();
+            long XX_configure_reg_c14n_start = System.currentTimeMillis();
+
+            {
+               Canonicalizer.init();
+
+               NodeList c14nElem = XPathAPI.selectNodeList(
+                  doc,
+                  "/x:Configuration/x:CanonicalizationMethods/x:CanonicalizationMethod",
+                  context);
+
+               for (int i = 0; i < c14nElem.getLength(); i++) {
+                  String URI = ((Element) c14nElem.item(i)).getAttributeNS(null,
+                                  "URI");
+                  String JAVACLASS =
+                     ((Element) c14nElem.item(i)).getAttributeNS(null,
+                        "JAVACLASS");
+                  boolean registerClass = true;
+
+                  try {
+                     Class c = Class.forName(JAVACLASS);
+                     Method methods[] = c.getMethods();
+
+                     for (int j = 0; j < methods.length; j++) {
+                        Method currMeth = methods[j];
+
+                        if (currMeth.getDeclaringClass().getName()
+                                .equals(JAVACLASS)) {
+                           log.debug(currMeth.getDeclaringClass());
+                        }
+                     }
+                  } catch (ClassNotFoundException e) {
+                     Object exArgs[] = { URI, JAVACLASS };
+
+                     log.fatal(I18n.translate("algorithm.classDoesNotExist",
+                                              exArgs));
+
+                     registerClass = false;
+                  }
+
+                  if (registerClass) {
+                     log.debug("Canonicalizer.register(" + URI + ", "
+                               + JAVACLASS + ")");
+                     Canonicalizer.register(URI, JAVACLASS);
+                  }
+               }
+            }
+
+            long XX_configure_reg_c14n_end = System.currentTimeMillis();
+            long XX_configure_reg_transforms_start = System.currentTimeMillis();
+
+            {
+               Transform.init();
+
+               NodeList tranElem = XPathAPI.selectNodeList(
+                  doc,
+                  "/x:Configuration/x:TransformAlgorithms/x:TransformAlgorithm",
+                  context);
+
+               for (int i = 0; i < tranElem.getLength(); i++) {
+                  String URI = ((Element) tranElem.item(i)).getAttributeNS(null,
+                                  "URI");
+                  String JAVACLASS =
+                     ((Element) tranElem.item(i)).getAttributeNS(null,
+                        "JAVACLASS");
+                  boolean registerClass = true;
+
+                  try {
+                     Class.forName(JAVACLASS);
+                  } catch (ClassNotFoundException e) {
+                     Object exArgs[] = { URI, JAVACLASS };
+
+                     log.fatal(I18n.translate("algorithm.classDoesNotExist",
+                                              exArgs));
+
+                     registerClass = false;
+                  }
+
+                  if (registerClass) {
+                     log.debug("Transform.register(" + URI + ", " + JAVACLASS
+                               + ")");
+                     Transform.register(URI, JAVACLASS);
+                  }
+               }
+            }
+
+            long XX_configure_reg_transforms_end = System.currentTimeMillis();
+            long XX_configure_reg_jcemapper_start = System.currentTimeMillis();
+
+            {
+               Element jcemapperElem = (Element) XPathAPI.selectSingleNode(
+                  doc, "/x:Configuration/x:JCEAlgorithmMappings", context);
+
+               JCEMapper.init(jcemapperElem);
+            }
+
+            long XX_configure_reg_jcemapper_end = System.currentTimeMillis();
+            long XX_configure_reg_sigalgos_start = System.currentTimeMillis();
+
+            {
+               SignatureAlgorithm.providerInit();
+
+               NodeList sigElems = XPathAPI.selectNodeList(
+                  doc,
+                  "/x:Configuration/x:SignatureAlgorithms/x:SignatureAlgorithm",
+                  context);
+
+               for (int i = 0; i < sigElems.getLength(); i++) {
+                  String URI = ((Element) sigElems.item(i)).getAttributeNS(null,
+                                  "URI");
+                  String JAVACLASS =
+                     ((Element) sigElems.item(i)).getAttributeNS(null,
+                        "JAVACLASS");
+
+                  /** $todo$ handle registering */
+                  boolean registerClass = true;
+
+                  try {
+                     Class c = Class.forName(JAVACLASS);
+                     Method methods[] = c.getMethods();
+
+                     for (int j = 0; j < methods.length; j++) {
+                        Method currMeth = methods[j];
+
+                        if (currMeth.getDeclaringClass().getName()
+                                .equals(JAVACLASS)) {
+                           log.debug(currMeth.getDeclaringClass());
+                        }
+                     }
+                  } catch (ClassNotFoundException e) {
+                     Object exArgs[] = { URI, JAVACLASS };
+
+                     log.fatal(I18n.translate("algorithm.classDoesNotExist",
+                                              exArgs));
+
+                     registerClass = false;
+                  }
+
+                  if (registerClass) {
+                     log.debug("SignatureAlgorithm.register(" + URI + ", "
+                               + JAVACLASS + ")");
+                     SignatureAlgorithm.register(URI, JAVACLASS);
+                  }
+               }
+            }
+
+            long XX_configure_reg_sigalgos_end = System.currentTimeMillis();
+            long XX_configure_reg_resourceresolver_start =
+               System.currentTimeMillis();
+
+            {
+               ResourceResolver.init();
+
+               NodeList resolverElem = XPathAPI.selectNodeList(
+                  doc, "/x:Configuration/x:ResourceResolvers/x:Resolver",
+                  context);
+
+               for (int i = 0; i < resolverElem.getLength(); i++) {
+                  String JAVACLASS =
+                     ((Element) resolverElem.item(i)).getAttributeNS(null,
+                        "JAVACLASS");
+                  String Description =
+                     ((Element) resolverElem.item(i)).getAttributeNS(null,
+                        "DESCRIPTION");
+
+                  if ((Description != null) && (Description.length() > 0)) {
+                     log.debug("Register Resolver: " + JAVACLASS + ": "
+                               + Description);
+                  } else {
+                     log.debug("Register Resolver: " + JAVACLASS
+                               + ": For unknown purposes");
+                  }
+
+                  ResourceResolver.register(JAVACLASS);
+               }
+            }
+
+            long XX_configure_reg_resourceresolver_end =
+               System.currentTimeMillis();
+            long XX_configure_reg_keyInfo_start = System.currentTimeMillis();
+
+            {
+               try {
+                  KeyInfo.init();
+
+                  Init._contentHandlerHash = new HashMap(10);
+
+                  {
+                     NodeList keyElem = XPathAPI.selectNodeList(
+                        doc, "/x:Configuration/x:KeyInfo/x:ContentHandler",
+                        context);
+
+                     for (int i = 0; i < keyElem.getLength(); i++) {
+                        String namespace =
+                           ((Element) keyElem.item(i)).getAttributeNS(null,
+                              "NAMESPACE");
+                        String localname =
+                           ((Element) keyElem.item(i)).getAttributeNS(null,
+                              "LOCALNAME");
+                        String JAVACLASS =
+                           ((Element) keyElem.item(i)).getAttributeNS(null,
+                              "JAVACLASS");
+
+                        log.debug("KeyInfoContent: " + namespace + " "
+                                  + localname + " " + JAVACLASS);
+                        Init.registerKeyInfoContentHandler(namespace,
+                                                           localname,
+                                                           JAVACLASS);
+                     }
+                  }
+               } catch (Exception e) {
+                  e.printStackTrace();
+
+                  throw e;
+               }
+            }
+
+            long XX_configure_reg_keyInfo_end = System.currentTimeMillis();
+            long XX_configure_reg_keyResolver_start =
+               System.currentTimeMillis();
+
+            {
+               KeyResolver.init();
+
+               NodeList resolverElem = XPathAPI.selectNodeList(
+                  doc, "/x:Configuration/x:KeyResolver/x:Resolver", context);
+
+               for (int i = 0; i < resolverElem.getLength(); i++) {
+                  String JAVACLASS =
+                     ((Element) resolverElem.item(i)).getAttributeNS(null,
+                        "JAVACLASS");
+                  String Description =
+                     ((Element) resolverElem.item(i)).getAttributeNS(null,
+                        "DESCRIPTION");
+
+                  if ((Description != null) && (Description.length() > 0)) {
+                     log.debug("Register Resolver: " + JAVACLASS + ": "
+                               + Description);
+                  } else {
+                     log.debug("Register Resolver: " + JAVACLASS
+                               + ": For unknown purposes");
+                  }
+
+                  KeyResolver.register(JAVACLASS);
+               }
+            }
+
+            long XX_configure_reg_keyResolver_end = System.currentTimeMillis();
+            long XX_configure_reg_prefixes_start = System.currentTimeMillis();
+
+            {
+               log.debug("Now I try to bind prefixes:");
+
+               NodeList nl = XPathAPI.selectNodeList(
+                  doc, "/x:Configuration/x:PrefixMappings/x:PrefixMapping",
+                  context);
+
+               for (int i = 0; i < nl.getLength(); i++) {
+                  String namespace = ((Element) nl.item(i)).getAttributeNS(null,
+                                        "namespace");
+                  String prefix = ((Element) nl.item(i)).getAttributeNS(null,
+                                     "prefix");
+
+                  log.debug("Now I try to bind " + prefix + " to " + namespace);
+                  org.apache.xml.security.utils.ElementProxy
+                     .setDefaultPrefix(namespace, prefix);
+               }
+            }
+
+            long XX_configure_reg_prefixes_end = System.currentTimeMillis();
+            long XX_init_end = System.currentTimeMillis();
+
+            //J-
+            log.debug("XX_init                             " + ((int)(XX_init_end - XX_init_start)) + " ms");
+            log.debug("  XX_prng                           " + ((int)(XX_prng_end - XX_prng_start)) + " ms");
+            log.debug("  XX_parsing                        " + ((int)(XX_parsing_end - XX_parsing_start)) + " ms");
+            log.debug("  XX_configure_i18n                 " + ((int)(XX_configure_i18n_end- XX_configure_i18n_start)) + " ms");
+            log.debug("  XX_configure_reg_c14n             " + ((int)(XX_configure_reg_c14n_end- XX_configure_reg_c14n_start)) + " ms");
+            log.debug("  XX_configure_reg_here             " + ((int)(XX_configure_reg_here_end- XX_configure_reg_here_start)) + " ms");
+            log.debug("  XX_configure_reg_jcemapper        " + ((int)(XX_configure_reg_jcemapper_end- XX_configure_reg_jcemapper_start)) + " ms");
+            log.debug("  XX_configure_reg_keyInfo          " + ((int)(XX_configure_reg_keyInfo_end- XX_configure_reg_keyInfo_start)) + " ms");
+            log.debug("  XX_configure_reg_keyResolver      " + ((int)(XX_configure_reg_keyResolver_end- XX_configure_reg_keyResolver_start)) + " ms");
+            log.debug("  XX_configure_reg_prefixes         " + ((int)(XX_configure_reg_prefixes_end- XX_configure_reg_prefixes_start)) + " ms");
+            log.debug("  XX_configure_reg_resourceresolver " + ((int)(XX_configure_reg_resourceresolver_end- XX_configure_reg_resourceresolver_start)) + " ms");
+            log.debug("  XX_configure_reg_sigalgos         " + ((int)(XX_configure_reg_sigalgos_end- XX_configure_reg_sigalgos_start)) + " ms");
+            log.debug("  XX_configure_reg_transforms       " + ((int)(XX_configure_reg_transforms_end- XX_configure_reg_transforms_start)) + " ms");
+            //J+
+         } catch (Exception e) {
+            log.fatal("Bad: ", e);
+            e.printStackTrace();
+         }
+      }
+   }
+
+   /**
+    * This method customizes the library with user supplied configuration.
+    * This includes access to keystores etc.
+    * By default, this method tries to find the configurationfile in
+    * the System.getProperty("user.home") directory.
+    *
+    * @throws XMLSecurityException
+    */
+   public static void readUserConfiguration() throws XMLSecurityException {
+
+      try {
+         String filename = System.getProperty("user.home") + "/"
+                           + Constants.configurationFileNew;
+         InputStream is = new FileInputStream(filename);
+
+         Init.readUserConfiguration(is);
+      } catch (IOException ex) {
+         throw new XMLSecurityException("generic.EmptyMessage", ex);
+      }
+   }
+
+   /**
+    * This method customizes the library with user supplied configuration.
+    * This includes access to keystores etc.
+    *
+    * @param fileURI
+    * @throws XMLSecurityException
+    */
+   public static void readUserConfiguration(String fileURI)
+           throws XMLSecurityException {
+
+      try {
+         InputStream is = null;
+
+         // first try to interpret fileURI as filename in the local file system
+         File f = new File(fileURI);
+
+         if (f.exists()) {
+            is = new FileInputStream(f);
+         } else {
+
+            // then treat it as USI
+            is = new java.net.URL(fileURI).openStream();
+         }
+
+         Init.readUserConfiguration(is);
+      } catch (IOException ex) {
+         throw new XMLSecurityException("generic.EmptyMessage", ex);
+      }
+   }
+
+   /**
+    * Method readUserConfiguration
+    *
+    * @param is
+    * @throws XMLSecurityException
+    */
+   public static void readUserConfiguration(InputStream is)
+           throws XMLSecurityException {
+
+      try {
+
+         /* read library configuration file */
+         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+
+         dbf.setNamespaceAware(true);
+         dbf.setValidating(false);
+
+         DocumentBuilder db = dbf.newDocumentBuilder();
+         Document doc = db.parse(is);
+         Element context = XMLUtils.createDSctx(
+            doc, "x", "http://www.xmlsecurity.org/NS/#configuration");
+
+         {
+            NodeList nl =
+               XPathAPI.selectNodeList(doc, "/x:AppConfiguration/x:KeyStore",
+                                       context);
+
+            for (int i = 0; i < nl.getLength(); i++) {
+               //EK: the registerStore method was already commented out.
+               //unsure what needs to happen with it now.
+               /*
+               Element e = (Element) nl.item(i);
+               String URI = e.getAttributeNS(null, "URI");
+               String keyStoreType = e.getAttributeNS(null, "Type");
+               String defaultKeyAlias = e.getAttributeNS(null,
+                                                         "DefaultKeyAlias");
+               String storePass = e.getAttributeNS(null, "StorePass");
+               String KeyPass = e.getAttributeNS(null, "KeyPass");
+               */
+
+               // org.apache.xml.security.keys.keyStorage.KeyStorage.registerStore(URI, JAVACLASS, LOCATION, DEFAULTKEYOBJECT, CONTEXT);
+            }
+         }
+      } catch (Exception ex) {
+         throw new XMLSecurityException("generic.EmptyMessage", ex);
+      }
+   }
+
+   /** Field _contentHandlerHash */
+   public static HashMap _contentHandlerHash;
+
+   /**
+    * Method registerKeyinfoContentHandler
+    *
+    * @param namespace
+    * @param localname
+    * @param implementingClass
+    * @throws ContentHandlerAlreadyRegisteredException
+    */
+   public static void registerKeyInfoContentHandler(
+           String namespace, String localname, String implementingClass)
+              throws ContentHandlerAlreadyRegisteredException {
+
+      String namespacequali = Init.qualifyNamespace(namespace, localname);
+
+      // are we already registered?
+      if (Init._contentHandlerHash.containsKey(namespacequali)) {
+         log.error("Already registered");
+
+         Object exArgs[] = { namespacequali,
+                             ((String) Init._contentHandlerHash
+                                .get(namespacequali)) };
+
+         throw new ContentHandlerAlreadyRegisteredException(
+            "algorithm.alreadyRegistered", exArgs);
+      }
+
+      synchronized (Init._contentHandlerHash) {
+         Init._contentHandlerHash.put(namespacequali, implementingClass);
+         log.debug("Init._contentHandlerHash.put(\"" + namespacequali
+                   + "\", \"" + implementingClass + "\")");
+         log.debug("Init._contentHandlerHash.size()="
+                   + Init._contentHandlerHash.size());
+      }
+   }
+
+   /**
+    * Method qualifyNamespace
+    *
+    * @param namespace
+    * @param localname
+    *
+    */
+   private static String qualifyNamespace(String namespace, String localname) {
+      return "{" + namespace + "}" + localname;
+   }
+
+   /**
+    * Method getContentHandlerClass
+    *
+    * @param namespace
+    * @param localname
+    *
+    */
+   public static String getKeyInfoContentHandler(String namespace,
+           String localname) {
+
+      /*
+      Iterator i = KeyInfo._contentHandlerHash.keySet().iterator();
+      while (i.hasNext()) {
+         String key = (String) i.next();
+         if (key.equals(URI)) {
+            return (String) KeyInfo._contentHandlerHash.get(key);
+         }
+      }
+      return null;
+      */
+      String namespacequali = Init.qualifyNamespace(namespace, localname);
+
+      log.debug("Asked for handler for " + namespacequali);
+
+      if (Init._contentHandlerHash == null) {
+         log.debug("But I can't help (hash==null) ");
+
+         return null;
+      }
+
+      if (Init._contentHandlerHash.size() == 0) {
+         log.debug("But I can't help (size()==0)");
+
+         return null;
+      }
+
+      Set keyset = Init._contentHandlerHash.keySet();
+      Iterator i = keyset.iterator();
+
+      while (i.hasNext()) {
+         String key = (String) i.next();
+
+         if (key.equals(namespacequali)) {
+            return (String) Init._contentHandlerHash.get(key);
+         }
+      }
+
+      return null;
+   }
+
+   /**
+    * Class FuncHereLoader
+    *
+    * @author $Author$
+    * @version $Revision$
+    */
+   public static class FuncHereLoader extends FuncLoader {
+
+      /**
+       * Constructor FuncHereLoader
+       *
+       */
+      public FuncHereLoader() {
+         super(FuncHere.class.getName(), 0);
+      }
+
+      /**
+       * Method getFunction
+       *
+       *
+       * @throws javax.xml.transform.TransformerException
+       */
+      public Function getFunction()
+              throws javax.xml.transform.TransformerException {
+         return new FuncHere();
+      }
+
+      /**
+       * Method getName
+       *
+       *
+       */
+      public String getName() {
+         return FuncHere.class.getName();
+      }
+   }
+}
+