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