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