Trabe ya no escribe aquí. Puedes encontrarnos en nuestra publicación en Medium: medium.com/trabe.

4Trabes Historias de una empresa en 100 metros cuadrados

El blog de Trabe Soluciones

Feeds RSS con Struts y RomeRSS

| | Comentarios

Sí amigos, Struts no está muerto, quizás superado, pero no muerto. Y como las cosas son así, hoy vamos a aprender (a la velocidad del galgo) como “montárnoslo” para servir feeds RSS desde nuestras acciones Struts utilizando la librería RomeRSS.

¿Para qué qerríamos hacer esto en lugar de servir los RSS a través de un Servlet específico? Sencillo. Para reaprovechar toda la infraestructura que tengamos montada para nuestra aplicación: superclases Action con comportamiento común, una cadena de filtros de preprocesado, etc, etc.

Mejor con un ejemplo. Vamos a procurar hacer las cosas de manera correcta, así que vamos a encapsular el uso de RomeRSS en una clase RSSFeeder para desacoplar nuestra aplicación de la librería. Algo así…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class RSSFeeder {

    private HttpServletRequest request = null;
    private HttpServletResponse response = null
    private SyndFeed feed = null;

    public RSSFeeder(HttpServletRequest request,
            HttpServletResponse response) {

        this.request = request;
        this.response = response;

        this.feed = new SyndFeedImpl();
        this.feed.setFeedType("rss_2.0");
        // ... más inicialización ...
    }

    public void setTitle(String title) {
        feed.setTitle(title);
    }

    // ... Y toda una "pléyade" the métodos set para establecer 
    // el contenido del RSS

    public void writeFeed() throws RSSFeederException {
        try {
            response.setStatus(HttpServletResponse.SC_OK);
            response.setContentType("application/xml;charset=utf-8");

            Writer writer = response.getWriter();
            SyndFeedOutput output = new SyndFeedOutput();
            output.output(feed, writer);
        } catch(Exception e) {
            throw new RSSFeederException(e);
        }
    }
}

No me paro en la generación del feed. Quién tenga interés por saber como se trabaja con RomeRSS puede echarle un ojo a su wiki.

Ahora nuestra acción de Struts…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public abstract class ExampleRSSAction extends BaseAction {

    public ActionForward doExecute(ActionMapping mapping,
            ActionForm form, HttpServletRequest request,
            HttpServletResponse response)
            throws IOException, ServletException, RSFeederException {

        RSSFeeder rssFeeder = new RSSFeeder(request, response);
        rssFeeder.setTitle("Example feed");
        // ... Más y más construcción del feed ...
        rssFeeder.writeFeed();

        return null;
    }
}

BaseAction es una clase plantilla que contiene código centralizado para la gestión de errores y otras cosas (el comportamiento común, vamos). Sus hijas sólo implementan el método doExecute que contiene la “chicha” de la acción.

Por último, el mapping en el satánico struts-config.xml.

1
2
3
<action path="/rss/example"
    type="com.trabesoluciones.app.controller.actions.rss.ExampleRSSAction"
    scope="request"/>

Listo. Tras el churro de código, la explicación. El secreto del éxito de esta empresa es romper el ciclo normal de Struts de petición, acción y forward/redirect (las acciones suelen devolver un objeto ActionForward). Para ello, nuestro feeder escribe directamente en el Writer de salida del servlet y nuestra acción devuelve un mágico null.

Y no lo olvidéis: si esto fuera un código de verdad: ¡¡COMENTARIOS!!

Pretty URLs en Java: Outbound rules con URLRewriteFilter

| | Comentarios

Hace ya algunos meses os hablamos de un interesante modo de conseguir URLs bonitas sin depender de Apache. Como se comenta en ese post, URLRewriteFilter puede ayudarnos a conseguir ese propósito.

Hoy nos hemos encontrado con un problema con las outbound rules: siguiendo escrupulosamente la documentación proporcionada en la página de URLRewriteFilter, no era posible hacer que las outbound rules con parámetros funcionasen correctamente. Según la documentación del filtro, una outbound rule se escribe tal que así:

1
2
3
4
<outbound-rule>
    <from>^/world.jsp?country=([a-z]+)&city=([a-z]+)$</from>
    <to>/world/$1/$2</to>
</outbound-rule>

Tras un buen rato tirándonos de los pelos y haciendo todo tipo de experimentos se nos encendió una lucecita. "¿Acaso el ‘?’ no tiene un significado específico en una expresión regular?¿No habría que escaparlo? Y escribimos la expresión escapando el ‘?’:

1
2
3
4
<outbound-rule>
    <from>^/world.jsp\?country=([a-z]+)&city=([a-z]+)$</from>
    <to>/world/$1/$2</to>
</outbound-rule>

Y todo comenzó a funcionar, con las limitaciones inherentes a este tipo de solución (que veremos en algún post futuro) pero correctamente.

Google Chart API + ruby = gchartrb

| | Comentarios

En nuestro último proyecto necesitamos incluir varios tipos de gráficas (líneas, barras y alguna tarta). De entre las múltiples posibilidades existentes hemos decidido usar el API de gráficas de Google (Google Chart API) que nos ofrece un montón de posibiliades de manera sencilla, fiable, gratuita e ilimitada. La única peculiaridad de su uso es que los datos a representar deben ser codificados antes de enviarlos al servidor de gráficas. Esto no representa mayor problema, menos aún cuando existen varios wrappers distribuidos como gemas o plugins que hacen este trabajo por nosotros, como son: gchartrb, Googlecharts o Google Charts on Rails.

Nosotros estamos usando gchartrb, porque entendemos es la más completa y documentada y porque su API nos agrada más. Por ejemplo, para pintar una sencilla gráfica como la que sigue…

… necesitamos un código como este:

1
2
3
4
5
6
7
8
9
10
11
PIE_COLORS = %w(9bd500 a4d520 b0d54b bbd575 c7d5a0)

data = Post.count(:group => :user_name, :order => 'count_all desc')

pie_chart = GoogleChart::PieChart.new('300x100') do |chart|
  data.each_with_index do |row, i|
     chart.data "#{row[0]} (#{row[1]})", row[1], PIE_COLORS[i]
  end
end

image_tag pie_chart.to_url