blob: 30fb2731946713d5cf8d940273329b802b49000b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.felix.ipojo.manipulation;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import org.apache.felix.ipojo.plugin.IPojoPluginConfiguration;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
/**
* iPOJO Bytecode Manipulator.
* @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
*
*/
public class Manipulator {
/**
* Store the visited fields : [name fo the field, type of the field].
*/
private HashMap m_fields = new HashMap();
/**
* Store the interface implemented by the class.
*/
private String[] m_interfaces = new String[0];
/**
* Store the methods list.
*/
private List m_methods = new ArrayList();
/**
* Return the hashmap [name of the field, type of the field].
* This information is found when the class is manipulated
* It is a clone of the original hashmap to avoid modification by handlers
* @return the hashmap [name of the field, type of the field].
*/
public HashMap getFields() {
return (HashMap)m_fields.clone();
}
/**
* Return the hashmap [name of the field, type of the field].
* This information is found when the class is manipulated
* It is a clone of the original hashmap to avoid modification by handlers
* @return the hashmap [name of the field, type of the field].
*/
public String[] getInterfaces() { return (String[])m_interfaces.clone(); }
/**
* @return the method list.
*/
public List getMethods() { return m_methods; }
/**
* Manipulate the class.
* @param name The name of the class
* @param cm The component manager attached to this manipulation
* @throws Exception : throwed if the manipulation failed.
*/
public boolean preProcess(String name, File outputDirectory) throws Exception {
// gets an input stream to read the bytecode of the class
String path = outputDirectory+"/"+name.replace('.', '/') + ".class";
File clazz = new File(path);
if(!clazz.exists()) { return false; }
URL url = clazz.toURI().toURL();
//if (url == null) { throw new ClassNotFoundException(name); }
IPojoPluginConfiguration.getLogger().log(Level.INFO, "Manipulate the class file : " + clazz.getAbsolutePath());
InputStream is1 = url.openStream();
// First check if the class is already manipulated :
ClassReader ckReader = new ClassReader(is1);
ClassChecker ck = new ClassChecker();
ckReader.accept(ck, true);
is1.close();
m_fields = ck.getFields();
// Get interface and remove POJO interface is presents
String[] its = ck.getInterfaces();
ArrayList l = new ArrayList();
for(int i = 0; i < its.length; i++) {
l.add(its[i]);
}
l.remove("org/apache/felix/ipojo/Pojo");
m_interfaces = new String[l.size()];
for (int i = 0; i < m_interfaces.length; i++) {
m_interfaces[i] = ((String) l.get(i)).replace('/', '.');
}
// Get the method list
// Remove iPOJO methods
for(int i = 0; i < ck.getMethods().size(); i++) {
MethodDescriptor method = (MethodDescriptor) ck.getMethods().get(i);
if(!(method.getName().startsWith("_get") || //Avoid getter method
method.getName().startsWith("_set") || // Avoid setter method
method.getName().equals("_setComponentManager") || // Avoid the set method
method.getName().equals("getComponentInstance"))){ // Avoid the getComponentInstance method
m_methods.add(method);
}
}
if(!ck.isalreadyManipulated()) {
//Manipulation ->
// Add the _setComponentManager method
// Instrument all fields
InputStream is2 = url.openStream();
ClassReader cr0 = new ClassReader(is2);
ClassWriter cw0 = new ClassWriter(true);
PreprocessClassAdapter preprocess = new PreprocessClassAdapter(cw0);
cr0.accept(preprocess, false);
is2.close();
try {
FileOutputStream fos = new FileOutputStream(clazz);
fos.write(cw0.toByteArray());
fos.close();
IPojoPluginConfiguration.getLogger().log(Level.INFO, "Put the file " + clazz.getAbsolutePath() + " in the jar file");
} catch (Exception e) { System.err.println("Problem to write the adapted class on the file system " + " [ "+ clazz.getAbsolutePath() +" ] " + e.getMessage()); }
}
// The file is in the bundle
return true;
}
}