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 021package org.apache.directory.api.ldap.sp; 022 023 024import java.io.File; 025import java.io.IOException; 026import java.io.InputStream; 027import java.io.Serializable; 028import java.net.URISyntaxException; 029import java.net.URL; 030 031import javax.naming.NamingException; 032import javax.naming.directory.Attributes; 033import javax.naming.directory.BasicAttributes; 034import javax.naming.ldap.ExtendedRequest; 035import javax.naming.ldap.ExtendedResponse; 036import javax.naming.ldap.LdapContext; 037 038import org.apache.commons.lang.SerializationUtils; 039import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory; 040import org.apache.directory.api.ldap.extras.extended.storedProcedure.StoredProcedureRequestImpl; 041import org.apache.directory.api.ldap.model.constants.SchemaConstants; 042import org.apache.directory.api.util.IOUtils; 043 044 045/** 046 * A utility class for working with Java Stored Procedures at the base level. 047 * 048 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 049 */ 050public final class JavaStoredProcUtils 051{ 052 053 /** 054 * Private constructor. 055 */ 056 private JavaStoredProcUtils() 057 { 058 } 059 060 061 /** 062 * Returns the stream data of a Java class. 063 * 064 * @param clazz 065 * The class whose stream data will be retrieved. 066 * @return 067 * Stream data of the class file as a byte array. 068 * @throws NamingException 069 * If an IO error occurs during reading the class file. 070 */ 071 public static byte[] getClassFileAsStream( Class<?> clazz ) throws NamingException 072 { 073 String fullClassName = clazz.getName(); 074 int lastDot = fullClassName.lastIndexOf( '.' ); 075 String classFileName = fullClassName.substring( lastDot + 1 ) + ".class"; 076 URL url = clazz.getResource( classFileName ); 077 InputStream in; 078 079 try 080 { 081 in = url.openStream(); 082 } 083 catch ( IOException ioe ) 084 { 085 NamingException ne = new NamingException(); 086 ne.setRootCause( ioe ); 087 throw ne; 088 } 089 090 File file; 091 092 try 093 { 094 file = new File( url.toURI() ); 095 } 096 catch ( URISyntaxException urie ) 097 { 098 NamingException ne = new NamingException(); 099 ne.setRootCause( urie ); 100 throw ne; 101 } 102 103 int size = ( int ) file.length(); 104 byte[] buf = new byte[size]; 105 106 try 107 { 108 in.read( buf ); 109 } 110 catch ( IOException e ) 111 { 112 NamingException ne = new NamingException(); 113 ne.setRootCause( e ); 114 throw ne; 115 } 116 finally 117 { 118 IOUtils.closeQuietly( in ); 119 } 120 121 return buf; 122 } 123 124 125 /** 126 * Loads a Java class's stream data as a subcontext of an LdapContext given. 127 * 128 * @param ctx 129 * The parent context of the Java class entry to be loaded. 130 * @param clazz 131 * Class to be loaded. 132 * @throws NamingException 133 * If an error occurs during creating the subcontext. 134 */ 135 public static void loadStoredProcedureClass( LdapContext ctx, Class<?> clazz ) throws NamingException 136 { 137 byte[] buf = getClassFileAsStream( clazz ); 138 String fullClassName = clazz.getName(); 139 140 Attributes attributes = new BasicAttributes( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, true ); 141 attributes.get( SchemaConstants.OBJECT_CLASS_AT ).add( "storedProcUnit" ); 142 attributes.get( SchemaConstants.OBJECT_CLASS_AT ).add( "javaStoredProcUnit" ); 143 attributes.put( "storedProcLangId", "Java" ); 144 attributes.put( "storedProcUnitName", fullClassName ); 145 attributes.put( "javaByteCode", buf ); 146 147 ctx.createSubcontext( "storedProcUnitName=" + fullClassName, attributes ); 148 } 149 150 151 /** 152 * Invoke a Stored Procedure 153 * 154 * @param ctx The execution context 155 * @param procedureName The procedure to execute 156 * @param arguments The procedure's arguments 157 * @return The execution resut 158 * @throws NamingException If we have had an error whil executing the stored procedure 159 */ 160 public static Object callStoredProcedure( LdapContext ctx, String procedureName, Object[] arguments ) 161 throws NamingException 162 { 163 String language = "Java"; 164 165 Object responseObject; 166 167 try 168 { 169 /** 170 * Create a new stored procedure execution request. 171 */ 172 StoredProcedureRequestImpl req = new StoredProcedureRequestImpl( 0, procedureName, language ); 173 174 /** 175 * For each argument UTF-8-encode the type name 176 * and Java-serialize the value 177 * and add them to the request as a parameter object. 178 */ 179 for ( int i = 0; i < arguments.length; i++ ) 180 { 181 byte[] type; 182 byte[] value; 183 type = arguments[i].getClass().getName().getBytes( "UTF-8" ); 184 value = SerializationUtils.serialize( ( Serializable ) arguments[i] ); 185 req.addParameter( type, value ); 186 } 187 188 /** 189 * Call the stored procedure via the extended operation 190 * and get back its return value. 191 */ 192 ExtendedRequest jndiReq = LdapApiServiceFactory.getSingleton().toJndi( req ); 193 ExtendedResponse resp = ctx.extendedOperation( jndiReq ); 194 195 /** 196 * Restore a Java object from the return value. 197 */ 198 byte[] responseStream = resp.getEncodedValue(); 199 responseObject = SerializationUtils.deserialize( responseStream ); 200 } 201 catch ( Exception e ) 202 { 203 NamingException ne = new NamingException(); 204 ne.setRootCause( e ); 205 throw ne; 206 } 207 208 return responseObject; 209 } 210}