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 }