Monthly Archives: April 2010

Escaneando anotaciones con Spring

Published / by Renan Huanca / 2 Comments on Escaneando anotaciones con Spring

Hola Amigos, acá comparto un poco de código que escribí esta semana.

El Problema

Esta semana estaba trabajando con AMF, mi problema era listar las classes que estaban anotadas con la anotación @RemotingDestination, para luego poder listarlas en una consola. (Con el objetivode mostrar los servicion AMF disponibles en el servidor)

Aca un ejemplo de una clase anotada con @RemotingDestination

package some.good.packague.to.work; // 🙂

import org.springframework.flex.remoting.RemotingDestination;
import org.springframework.stereotype.Service;

@Service("userService")
@RemotingDestination
public class UserService{

    public String getUserName(String userId) {
        .....
        return "The best name in the world :)";
    }

}

La Solución

Primeramente estaba viendo Javassist, pero al final me quede con una solución con Spring.

El ejemplo lo encontré el blog de Java Chimaera, pero le hice algunas modificaciones para que ahora soporte buscar clases tanto en linux como en windows.

El Código

package yep.this.is.a.very.good.package;

import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.ClassUtils;

import java.util.Set;
import java.util.HashSet;
import java.io.IOException;

/**
 * This class is a adaptation of:
 *
 *    http://java-chimaera.blogspot.com/2008/10/scanning-classpath-annotated-classes.html
 */
/**
 * @author Renan Huanca
 * @since Apr 16, 2010 9:52:12 PM
 */
public class AnnotatedClassFinder {
    private String basePackage;
    private ResourcePatternResolver resourceResolver = null;
    private MetadataReaderFactory metadataReaderFactory = null;
    private TypeFilter annotationFilter = null;
    
    public AnnotatedClassFinder(String basePackage) {
        this.basePackage = basePackage;
        this.resourceResolver = new PathMatchingResourcePatternResolver(
                Thread.currentThread().getContextClassLoader());
        this.metadataReaderFactory = new SimpleMetadataReaderFactory();
    }

    public static AnnotatedClassFinder getInstance(String basePackage){
        return new AnnotatedClassFinder(basePackage);
    }

    public Set findByAnnotation(Class annotation) {
        this.annotationFilter = new AnnotationTypeFilter(annotation);
        Set annotatedClasses = new HashSet();
        /*
        * First of all we load all resources that are under a specific package by using a ResourcePatternResolver.
        * By doing so we will use class files as simple resources without passing
        * by the ClassLoader which can for example cause the execution of a static initialization block.
        * It resolves also transparently resources in jars.
        */
        String candidateClassesLocationPattern = "classpath*:" + basePackage + "/**/*.class";
        Resource[] resources = null;
        try {
            resources = resourceResolver.getResources(candidateClassesLocationPattern);
        } catch (IOException e) {
            throw new RuntimeException(
                    "An I/O problem occurs when trying to resolve ressources matching the pattern : "
                            + candidateClassesLocationPattern, e);
        }

        /*
        * then we proceed resource by resource, using a MetadataReaderFactory to create
        * MetadataReader wich hides the ASM related interface and complexity.
        *
        */
        for (Resource resource : resources) {
            MetadataReader metadataReader = null;
            try {
                metadataReader = this.metadataReaderFactory.getMetadataReader(resource);

                if (this.annotationFilter.match(metadataReader, metadataReaderFactory)) {

                    /*
                    * the AnnotationMetadata is a simple abstaction of the informations
                    * that holds the annotation
                    */
                    String className = convertResourceToClassName(resource, basePackage);
                    try {
                        annotatedClasses.add(ClassUtils.forName(className));
                    } catch (Exception e) {
                        throw new RuntimeException("problems occurs when trying to load the annotated class : " + className, e);
                    }
                }
            } catch (IOException e) {
                throw new RuntimeException("An I/O problem occurs when trying to process resource : " + resource, e);
            }
        }

        return annotatedClasses;
    }

    static String convertResourceToClassName(Resource resource, String basePackage) throws IOException {
        String path = resource.getFile().getPath();
        String pathWithoutSuffix = path.substring(0, path.length() - ClassUtils.CLASS_FILE_SUFFIX.length());
        String relativePathWithoutSuffix = "";
        if(System.getProperty("file.separator").equals("\\")) {
            relativePathWithoutSuffix = pathWithoutSuffix.substring(pathWithoutSuffix.indexOf(basePackage.replace('/', '\\')));
            relativePathWithoutSuffix = relativePathWithoutSuffix.replace('\\', '/');
        } else if(System.getProperty("file.separator").equals("//")) {
            relativePathWithoutSuffix = pathWithoutSuffix.substring(pathWithoutSuffix.indexOf(basePackage));
        } else {
            throw new RuntimeException("File separator is not recognized");
        }

        // taking out extra \ or /
        relativePathWithoutSuffix = relativePathWithoutSuffix.substring(1);

        return relativePathWithoutSuffix.replace('/', '.');
    }
}

Como llamarlo?

AnnotatedClassFinder finder = AnnotatedClassFinder.getInstance("/the/package/you/want/to/search");
Set classes = finder.findByAnnotation(RemotingDestination.class);

Convertir PDF a SWF con AIR 2 beta

Published / by Renan Huanca / 4 Comments on Convertir PDF a SWF con AIR 2 beta

Introducción

Hola Amigos, acá comparto una la solución a un problema que tuve esta semana. Se trata de convertir un archivo PDF al formato flash SWF.

Aca un resumen de los problemas:

  1. No existe (al momento) una forma nativa dentro de AIR para convertir un archivo pdf a swf, entonces tuve que hacer la llamada al comando pdf2swf.exe (SWFTools) desde AIR
  2. La opcion de ejecutar comandos de linea solo esta disponible en Adobe AIR 2 Beta (al momento), entonces me anime a usar la versión beta

El código

import __AS3__.vec.Vector;

import flash.desktop.NativeProcess;
import flash.desktop.NativeProcessStartupInfo;
import flash.events.IOErrorEvent;
import flash.events.NativeProcessExitEvent;
import flash.events.ProgressEvent;
import flash.events.TimerEvent;
import flash.filesystem.File;
import flash.utils.Timer;

import mx.core.FlexGlobals;

public class PDF2SWFConverter
{
	private var command:String;
	private var finished:Boolean = false;
	private var error:Boolean = false;
	private var timer:Timer;
	
	public function PDF2SWFConverter(command:String)
	{
		this.command = command;	
	}
	
	public static function getInstance():PDF2SWFConverter{
		return new PDF2SWFConverter("/path/to/pdf2swf.exe");	
	} 
	
	public function convert(pdfPath:String, swfPath:String):Boolean {
		var nativeProcessStartupInfo:NativeProcessStartupInfo =  new NativeProcessStartupInfo();
		var commandFile:File = new File(command); 
		nativeProcessStartupInfo.executable = commandFile;
		var args:Vector. = new Vector.();
		args.push(pdfPath);
		args.push("-t");
		args.push("-T9");
		args.push("-o");
		args.push(swfPath);
		
		nativeProcessStartupInfo.arguments = args;
		var process:NativeProcess;

		timer = new Timer(1);

		process = new NativeProcess();
		process.start(nativeProcessStartupInfo);
		process.addEventListener(NativeProcessExitEvent.EXIT, onExit);
		process.addEventListener(ProgressEvent.STANDARD_ERROR_DATA, onErrorData);
		process.addEventListener(IOErrorEvent.STANDARD_ERROR_IO_ERROR, onIOError);
		
		timer.addEventListener(TimerEvent.TIMER, myTimerHandler);

		this.finished = false;
		this.error = false;
		timer.start();

		return !error;
	}
	
	protected function onExit(event:NativeProcessExitEvent):void
	{
		this.finished = true;
	}
	
	public function onErrorData(event:ProgressEvent):void
	{
      		this.error = true;
          		this.finished = true; 
      	}
	
	public function onIOError(event:IOErrorEvent):void
      	{
      		this.error = true;
      		this.finished = true;
      	}
      
      	public function myTimerHandler(e:TimerEvent):void{
      		if(this.finished)
		{
			timer.stop();
		} 
	}
}

Convertir PDF a SWF

Para llamar desde Flex al comando pdf2swf.exe, usamos los objectos: NativeProcessStartupInfo y NativeProcess.

NativeProcessStartupInfo, nos permite definir la información inicial de la llamada (nombre de comando y parametros) a un comando de linea. Este objecto es usado como parámetro para el método start del objeto NativeProcess.

NativeProcess, nos permite realizar la llamada a un comando de linea. Cabe advertir que por motivos de seguridad, no es posible ejecutar archivos .bat.

También es necesario señalar que para ejecutar de comandos de linea la aplicacion AIR tiene que tener configurado el perfil de escritorio extendido. Para esto tenemos que añadir lo siguiente al app.xml de la aplicacion AIR:

extendedDesktop

Como llamar a PDF2SWFConverter

Para llamar al objecto basta con lo siguiente:

var converter:PDF2SWFConverter = PDF2SWFConverter.getInstance();
converter.convert("/path/to/doc.pdf","/path/to/new/doc.swf");

Esta clase es un wrapper (envoltura) para el comando, la ventaja es que uno puede llamar a la clase, ejecutar la conversión y continuar con la secuencia de instrucciones gracias a que se usa el el objeto Timer.