blob: c572169f9def449d0ffba61f2888d97c46dfa32d [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.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.felix.ipojo.metadata.Attribute;
import org.apache.felix.ipojo.metadata.Element;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
/**
* iPOJO Byte code Manipulator.
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*
*/
public class Manipulator {
/**
* Store the visited fields : [name of the field, type of the field].
*/
private Map m_fields;
/**
* Store the interface implemented by the class.
*/
private List m_interfaces;
/**
* Store the methods list.
*/
private List m_methods;
/**
* Pojo super class.
*/
private String m_superClass;
/**
* List of owned inner classed.
*/
private List m_inners;
/**
* Manipulate the given byte array.
* @param origin : original class.
* @return the manipulated class.
* @throws IOException : if an error occurs during the manipulation.
*/
public byte[] manipulate(byte[] origin) throws IOException {
InputStream is1 = new ByteArrayInputStream(origin);
// First check if the class is already manipulated :
ClassReader ckReader = new ClassReader(is1);
ClassChecker ck = new ClassChecker();
ckReader.accept(ck, ClassReader.SKIP_FRAMES);
is1.close();
m_fields = ck.getFields(); // Get visited fields (contains only POJO fields)
// Get interfaces and super class.
m_interfaces = ck.getInterfaces();
m_superClass = ck.getSuperClass();
// Get the methods list
m_methods = ck.getMethods();
m_inners = ck.getInnerClasses();
ClassWriter finalWriter = null;
if (!ck.isalreadyManipulated()) {
// Manipulation ->
// Add the _setComponentManager method
// Instrument all fields
InputStream is2 = new ByteArrayInputStream(origin);
ClassReader cr0 = new ClassReader(is2);
ClassWriter cw0 = new ClassWriter(ClassWriter.COMPUTE_MAXS);
//CheckClassAdapter ch = new CheckClassAdapter(cw0);
MethodCreator preprocess = new MethodCreator(cw0, m_fields, m_methods);
cr0.accept(preprocess, ClassReader.SKIP_FRAMES);
is2.close();
finalWriter = cw0;
}
// The file is in the bundle
if (ck.isalreadyManipulated()) {
return new byte[0];
} else {
return finalWriter.toByteArray();
}
}
/**
* Compute component type manipulation metadata.
* @return the manipulation metadata of the class.
*/
public Element getManipulationMetadata() {
Element elem = new Element("Manipulation", "");
if (m_superClass != null) {
elem.addAttribute(new Attribute("super", m_superClass));
}
for (int j = 0; j < m_interfaces.size(); j++) {
Element itf = new Element("Interface", "");
Attribute att = new Attribute("name", m_interfaces.get(j).toString());
itf.addAttribute(att);
elem.addElement(itf);
}
for (Iterator it = m_fields.keySet().iterator(); it.hasNext();) {
Element field = new Element("Field", "");
String name = (String) it.next();
String type = (String) m_fields.get(name);
Attribute attName = new Attribute("name", name);
Attribute attType = new Attribute("type", type);
field.addAttribute(attName);
field.addAttribute(attType);
elem.addElement(field);
}
for (int j = 0; j < m_methods.size(); j++) {
MethodDescriptor method = (MethodDescriptor) m_methods.get(j);
elem.addElement(method.getElement());
}
return elem;
}
public Map getFields() {
return m_fields;
}
public List getInnerClasses() {
return m_inners;
}
}