001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 */
020
021
022 package org.apache.directory.shared.ldap.sp;
023
024 import java.io.File;
025 import java.io.IOException;
026 import java.io.InputStream;
027 import java.io.Serializable;
028 import java.net.URL;
029
030 import javax.naming.NamingException;
031 import javax.naming.directory.Attributes;
032 import javax.naming.directory.BasicAttributes;
033 import javax.naming.ldap.LdapContext;
034
035 import org.apache.commons.lang.SerializationUtils;
036 import org.apache.directory.shared.ldap.constants.SchemaConstants;
037 import org.apache.directory.shared.ldap.message.extended.StoredProcedureRequest;
038 import org.apache.directory.shared.ldap.message.extended.StoredProcedureResponse;
039
040 /**
041 * A utility class for working with Java Stored Procedures at the base level.
042 *
043 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
044 * @version $Rev:$
045 */
046 public class JavaStoredProcUtils
047 {
048
049
050 /**
051 * Returns the stream data of a Java class.
052 *
053 * @param clazz
054 * The class whose stream data will be retrieved.
055 * @return
056 * Stream data of the class file as a byte array.
057 * @throws NamingException
058 * If an IO error occurs during reading the class file.
059 */
060 public static byte[] getClassFileAsStream( Class<?> clazz ) throws NamingException
061 {
062 String fullClassName = clazz.getName();
063 int lastDot = fullClassName.lastIndexOf( '.' );
064 String classFileName = fullClassName.substring( lastDot + 1 ) + ".class";
065 URL url = clazz.getResource( classFileName );
066 InputStream in = clazz.getResourceAsStream( classFileName );
067 File file = new File( url.getFile() );
068 int size = ( int ) file.length();
069 byte[] buf = new byte[size];
070
071 try
072 {
073 in.read( buf );
074 in.close();
075 }
076 catch ( IOException e )
077 {
078 NamingException ne = new NamingException();
079 ne.setRootCause( e );
080 throw ne;
081 }
082
083 return buf;
084 }
085
086 /**
087 * Loads a Java class's stream data as a subcontext of an LdapContext given.
088 *
089 * @param ctx
090 * The parent context of the Java class entry to be loaded.
091 * @param clazz
092 * Class to be loaded.
093 * @throws NamingException
094 * If an error occurs during creating the subcontext.
095 */
096 public static void loadStoredProcedureClass( LdapContext ctx, Class<?> clazz ) throws NamingException
097 {
098 byte[] buf = getClassFileAsStream( clazz );
099 String fullClassName = clazz.getName();
100
101 Attributes attributes = new BasicAttributes( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, true );
102 attributes.get( SchemaConstants.OBJECT_CLASS_AT ).add( "storedProcUnit" );
103 attributes.get( SchemaConstants.OBJECT_CLASS_AT ).add( "javaStoredProcUnit" );
104 attributes.put( "storedProcLangId", "Java" );
105 attributes.put( "storedProcUnitName", fullClassName );
106 attributes.put( "javaByteCode", buf );
107
108 ctx.createSubcontext( "storedProcUnitName=" + fullClassName , attributes );
109 }
110
111 public static Object callStoredProcedure( LdapContext ctx, String procedureName, Object[] arguments ) throws NamingException
112 {
113 String language = "Java";
114
115 Object responseObject;
116 try
117 {
118 /**
119 * Create a new stored procedure execution request.
120 */
121 StoredProcedureRequest req = new StoredProcedureRequest( 0, procedureName, language );
122
123 /**
124 * For each argument UTF-8-encode the type name
125 * and Java-serialize the value
126 * and add them to the request as a parameter object.
127 */
128 for ( int i = 0; i < arguments.length; i++ )
129 {
130 byte[] type;
131 byte[] value;
132 type = arguments[i].getClass().getName().getBytes( "UTF-8" );
133 value = SerializationUtils.serialize( ( Serializable ) arguments[i] );
134 req.addParameter( type, value );
135 }
136
137 /**
138 * Call the stored procedure via the extended operation
139 * and get back its return value.
140 */
141 StoredProcedureResponse resp = ( StoredProcedureResponse ) ctx.extendedOperation( req );
142
143 /**
144 * Restore a Java object from the return value.
145 */
146 byte[] responseStream = resp.getEncodedValue();
147 responseObject = SerializationUtils.deserialize( responseStream );
148 }
149 catch ( Exception e )
150 {
151 NamingException ne = new NamingException();
152 ne.setRootCause( e );
153 throw ne;
154 }
155
156 return responseObject;
157 }
158
159 }