Problem z utworzeniem projektu Spring Roo (STS @ Ubuntu)

2 sierpnia 2010 30 Komentarzy

Postanowiłem wypróbować Spring Roo. Żeby ułatwić sobie pracę z projektem pobrałem środowisko STS (SpringSource Tool Suite 2.3.2.RELEASE) wersja na Linuxa 64 bit (korzystam z Ubuntu 9.04).

Instalacja środowiska przebiegła bez problemów, uruchomienie również, dodatkowo ustaliłem sobie scieżkę systemową do katalogu z Roo. Schody zaczęły się w momencie tworzenia nowego projektu Roo. Podałem „project name” oraz „top level package name”, i po kliknięciu na „finish” nic się nie pojawiło. Żadnego projektu w „project explorer”, żadnych błędów. Konsoli Roo też nie mogłem otworzyć bo nie widziała żadnych projektów.

W katalogu w którym miał zostać utworzony projekt znalazły się trzy pliki i jeden katalog (log, .classpath, .project oraz .settings).

W związku z tym że w sieci nie znalazłem żadnych informacji na ten temat, projekt Roo utworzyłem samodzielnie w konsoli, a następnie wczytałem go do STS’a przez:
New -> Project -> General -> Project, a następnie w polu „Location” wybrałem ścieżkę do projektu.
W tym momencie dostałem komunikat (nie pamiętam dokładnie treści) z pytaniem czy włączyć jakąś usługę (JDT Weaving), oczywiście potwierdziłem, środowisko zostało zrestartowane, a projekt wczytany. System zwrócił również komunikat „The JDT Weaving service has been enabled”.
Następnie z poziomu STS’a ponownie spróbowałem utworzyć nowy projekt Roo i tym razem się udało (trochę to trwało bo STS przebudowywał workspace). Kolejne projekty są tworzone bardzo szybko. Konsola Roo uruchamia się poprawnie dla każdego projektu.

Mam nadzieję ten wpis jeszcze się komuś przyda 🙂

Kategorie:Spring Roo, STS, Ubuntu Tagi: , ,

symfony – problemy po konfiguracji bazy danych

11 czerwca 2010 155 Komentarzy

Dzisiaj trochę z innej beczki. Właśnie próbuję przejrzeć tutorial symfony 1.4 (jobeet) + propel. Ledwo doszedłem do 3 rozdziału a już problemy 😉 O co chodzi. Chciałem wykonać wykonać następujące polecenie (system Ubuntu):

symfony propel:insert-sql

Komenda ta zwróciła następujący błąd:

[propel-sql-exec] Failed to execute:
[propel-sql-exec] SQLSTATE[3D000]: Invalid catalog name: 1046 No database selected
[propel-sql-exec] Failed to execute:

A przecież wcześniej konfigurowałem połączenie poleceniem (zgodnie z tym co pisze w tutorialu):

symfony configure:database "mysql:host=localhost;dbname=jobeet" root mojeHaslo

Pliki database.yml i propel.ini zostały poprawnie wygenerowane.
Co się okazuje wystarczy tylko zmienić kolejność w powyższym poleceniu, czyli nazwa bazy na początek:

symfony configure:database "mysql:dbname=jobeet;host=localhost" root mojeHaslo

I teraz wszystko działa. Krótka notka ale może komuś się przyda 🙂

Kategorie:PHP, symfony

Spring Framework 3 + SiteMesh 3 – pierwsze starcie

2 czerwca 2010 23 Komentarze

Po dłuższej przerwie czas wrócić do pisania 🙂 Wprawdzie praca magisterska jeszcze nie skończona ale jest trochę luźniej i czas na jakiś mądry 😉 wpis.

Ostatnio jeden blogerów Darek Zoń zaczął na swoim blogu pisać tutorial o tworzeniu aplikacji w Spring Framework z wykorzystaniem SiteMesh i Hibernate. Zainteresowałem się tematem i podzielę się się wrażeniami z pierwszego starcia z tymi narzędziami.

Swój projekt rozpocząłem w NetBeans 6.9 RC 2 (ma wsparcie dla Spring Framework 3, do projektu są automatycznie dodane biblioteki wersji 3.0.2). Do utworzenia aplikacji konieczne jest pobranie biblioteki SiteMesh (wersja alpha).

Standardowo tworzymy nowy projekt wykonując następujące kroki

  • New project
  • Java Web -> WebApplication
  • serwer może być domyślny (Apache)
  • zaznaczamy Spring Web MVC i w konfiguracji wybieramy wersję 3

W związku z tym że nowy Spring Framework pozwala na tworzenie kontrolerów poprzez adnotację @Controller w pliku konfiguracyjnym trzeba dodać odpowiednie opcje które na to pozwolą.

W pliku dispatcher-servlet.xml należy dodać poniższy kod:

</span></span>
<pre><pre><context:component-scan base-package="eu.ryznar.controller" />
<context:annotation-config />
<context:spring-configured />

Próba umieszczenia takiego projektu na serwerze zwróci wyjątek w postaci (fragment):

org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 13 in XML document from ServletContext resource [/WEB-INF/dispatcher-servlet.xml] is invalid; nested exception is org.xml.sax.SAXParseException: The prefix "context" for element "context:component-scan" is not bound.
.
.
.
Caused by: org.xml.sax.SAXParseException: The prefix "context" for element "context:component-scan" is not bound.
.
.
.
2010-06-02 12:25:23 org.apache.catalina.core.StandardContext loadOnStartup
SEVERE: Servlet /WebApp1 threw load() exception
org.xml.sax.SAXParseException: The prefix "context" for element "context:component-scan" is not bound.

Aby się tego „pozbyć” w tym samym pliku w sekcji beans należy dodać:

xmlns:context="http://www.springframework.org/schema/context"

Oraz do xsi:schemaLocation dopisać:

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd

Teraz można dodać kontroler we wskazanej wcześniej paczce:

package eu.ryznar.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class IndexController {

    @RequestMapping(value="/index")
    public ModelAndView index() {
        ModelAndView mv = new ModelAndView("hello");

        return mv;
    }
}

oraz utworzyć plik hello.jsp w katalogu /WEB-INF/jsp:

<html>
  <head>
    <title>Hello World</title>
    <meta name='description' content='A simple page'>
  </head>
  <body>
    <p>Hello <strong>world</strong>!</p>
  </body>
</html>

Próba uruchomienia takiej aplikacje rzuca kolejny wyjątek (fragment):

java.lang.NoClassDefFoundError: org/aspectj/lang/NoAspectBoundException
.
.
.
Caused by: java.lang.ClassNotFoundException: org.aspectj.lang.NoAspectBoundException
.
.
.
2010-06-01 22:43:05 org.apache.catalina.core.StandardContext loadOnStartup
SEVERE: Servlet /WebApp1 threw load() exception
java.lang.ClassNotFoundException: org.aspectj.lang.NoAspectBoundException

Brakuje nam biblioteki AspectJ. Należy ją pobrać ze strony http://eclipse.org/aspectj .
Pobrany plik należy wypakować, i do bibliotek tworzonego projektu dodać plik jar: aspectjrt.jar.

Teraz można uruchomić aplikację, i po wpisaniu adresu (port zależny od serwera) http://localhost:8084/WebApp1/index.html strona zostanie wyświetlona poprawnie.

Czas na SiteMesh. Do bibliotek projektu należy dodać pobrane archiwum jar.
Działania SiteMesh nie będę omawiał, pokażę tylko konfigurację. Autor wskazanego bloga użył konfiguracji opartej o klasę Java, mi jednak udało się z samą konfiguracją xml. Tzn. w pliku web.xml dodajemy odpowiednie filtry:

  <filter>
    <filter-name>sitemesh</filter-name>
    <filter-class>org.sitemesh.config.ConfigurableSiteMeshFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>sitemesh</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

I dodatkowo tworzymy plik sitemesh3.xml (w tej samej ścieżce co web.xml) o następującej zawartości:

<?xml version="1.0" encoding="UTF-8"?>
<sitemesh>
  <mapping path="/*" decorator="/WEB-INF/jsp/decorator.jsp"/>
</sitemesh>

Plik który widnieje w konfiguracji decorator.jsp trzeba stworzyć we wskazanej ścieżce. Odgrywa on rolę szablonu, wg którego budowane są podstrony. Przykładowa zawartość pliku.

<html>
  <head>
    <title>SiteMesh example: <sitemesh:write property='title'/></title>
    <style type='text/css'>
      /* Some CSS */
      body { font-family: arial, sans-serif; background-color: #ffffcc; }
      h1, h2, h3, h4 { text-align: center; background-color: #ccffcc; border-top: 1px solid #66ff66; }
      .mainBody { padding: 10px; border: 1px solid #555555; }
      .disclaimer { text-align: center; border-top: 1px solid #cccccc; margin-top: 40px; color: #666666; font-size: smaller; }
    </style>
    <sitemesh:write property='head'/>
  </head>
  <body>

    <h1 class='title'>SiteMesh example site: <sitemesh:write property='title'/></h1>

    <div class='mainBody'>
      <sitemesh:write property='body'/>
    </div>

    <div class='disclaimer'>Site disclaimer. This is an example.</div>

  </body>
</html>

To wszytko. Można odświeżyć wcześniej uruchomioną stronę i zobaczymy ładnie sformatowaną stronę z „Hello World”.

Jeśli coś źle napisałem będę wdzięczny za uwagi.

java seo friendly url (slug)

31 stycznia 2010 77 Komentarzy

Tworząc aplikację internetową, często w adresach pojawia się jakiś tekst, np tytuł wprowadzony przez użytkownika podczas dodawania artykuły, chociażby blogi na wordpressie.
Jednak adres w postaci http://www.ryznar.eu/artykul/śmieszny-artykuł podobno jest gorzej odbierany przez google, dwa w niektórych przeglądarkach jest on niezbyt czytelny bo przeglądarka nie potrafi przetworzyć np.: IE.
Dlatego tekst wprowadzony przez użytkownika należy nieco zmodyfikować. Z racji ze potrzebuję takiej funkcji napisałem sobie odpowiednią klasę:

import java.text.Normalizer;
import java.text.Normalizer.Form;

public class Slug {

    public static String parse(String input) {
        if (isEmptyOrNull(input)) {
            return "";
        }
        String out = normalize(input);
        out = removeDuplicateWhiteSpaces(out);
        out = out.toLowerCase();
        out = out.replace(" ", "-");

        return out;
    }

    private static String normalize(String input) {
        String result = Normalizer.normalize(input, Form.NFD).replaceAll("[^\\p{ASCII}]", ""); // 1
        result = result.replaceAll("[^a-zA-Z0-9\\s]", " "); // 2

        return result;
    }

    private static String removeDuplicateWhiteSpaces(String input) {
        return input.replaceAll("\\s+", " ");
    }

    private static boolean isEmptyOrNull(String input) {
        return (input == null || input.trim().length() == 0);
    }
}

1) tekst jest normalizowany, tzn znaki diakrytyczne są zmieniane na znaki ASCII
2) tutaj zmieniamy wszystkie znaki niealfanumeryczne na spacje

Możemy przetestować klasę:

        String inputText = "123-test       nąśŹA       zima 🙂 !! #@ zła";
        System.out.println(inputText);
        System.out.println(Slug.parse(inputText));

wynik: 123-test-nasza-zima-za – zjadło literkę „l”
okazuje się że na l może być zamieniony a nie ł
Niestety w sieci nie widzę żadnej wskazówki jak ładnie rozwiązać ten problem, więc na razie pozostaje mi tylko zmodyfikować ciało funkcji normalize:

        String result = input.replace("ł", "l").replace("Ł", "L");

        result = Normalizer.normalize(result, Form.NFD).replaceAll("[^\\p{ASCII}]", ""); // 1
        result = result.replaceAll("[^a-zA-Z0-9\\s]", " "); // 2

jeśli ktoś wie jak to zrobić normalnie a nie poprzez takie kombinacje, będę wdzięczny za komentarz

Kategorie:Java Tagi: , , ,

JMS tutorial – krótkie wprowadzenie

7 grudnia 2009 118 Komentarzy

JMS (Java Message Service) każdy wie co to jest 😉 a jak nie to warto sprawdzić w wikipedii 🙂
JMS wspiera dwa typy komunikatów (messaging models).
W każdym mamy klienta [message consumer] i dostawcę [message procuder].
Te typy to:
1. Point to point [czyli jeden do jednego] – komunikaty są wysyłane przez kolejki [queues] – tutaj dostawcę nazywamy producer, a klienta receiver
2. Publish and subscribe [czyli jeden do wielu] – komunikaty są wysyłane to kanału [topic] – tutaj dostawcę nazywamy publisher a klienta subscriber

W obu przypadkach komunikaty mogą być wysyłane synchronicznie jak i asynchronicznie.

JMS API podzielone jest na trzy części
API ogólne(?) tzn:
ConnectionFactory
Destination
Connection
Session
Message
MessageProducer
MessageConsumer

Point to point:
QueueConnectionFactory
Queue
QueueConnection
QueueSession
Message
QueueSender
QueueReceiver

Publish and subscribe:
TopicConnectionFactory
Topic
TopicConnection
TopicSession
Message
TopicPublisher
TopicSubscriber

Spośród dostępnych implementacji JMS wybrałem ActiveMQ [to tzw „message broker”] – wersję 5.3 można pobrać tutaj

Uruchomienie ActiveMQ jest bardzo proste, wystarczy rozpakować pobrane archiwum i w katalogu bin, z konsoli wywołać polecenie

./activemq

w konsoli podczas uruchamiania mniej więcej pojawia się coś takiego

 INFO | Using Persistence Adapter: org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter@26a7dd39
 INFO | Replayed 1 operations from the journal in 0.016 seconds.
 INFO | ActiveMQ 5.3.0 JMS Message Broker (localhost) is starting
 INFO | For help or more information please see: http://activemq.apache.org/
 INFO | Listening for connections at: tcp://enigma-ubu:61616
 INFO | Connector openwire Started
 INFO | ActiveMQ JMS Message Broker (localhost, ID:enigma-ubu-40003-1260214060614-0:0) started
 INFO | Logging to org.slf4j.impl.JCLLoggerAdapter(org.mortbay.log) via org.mortbay.log.Slf4jLog
 INFO | jetty-6.1.9
 INFO | ActiveMQ WebConsole initialized.
 INFO | Initializing Spring FrameworkServlet 'dispatcher'
 INFO | ActiveMQ Console at http://0.0.0.0:8161/admin
 INFO | Initializing Spring root WebApplicationContext
 INFO | Connector vm://localhost Started
 INFO | Camel Console at http://0.0.0.0:8161/camel
 INFO | ActiveMQ Web Demos at http://0.0.0.0:8161/demo
 INFO | RESTful file access application at http://0.0.0.0:8161/fileserver
 INFO | Started SelectChannelConnector@0.0.0.0:8161

teraz w przeglądarce można sprawdzić adres http://localhost:8161/admin/index.jsp


Czas na przykładową aplikację, korzystającą z ogólnego API. Aplikacja będzie bardzo prosta, tylko wyśle jeden komunikat.
Tworzymy nowy projekt Java -> Java Application
Następnie do bibliotek dodajemy plik activemq-all-5.3.0.jar [znajduje się w pobranym archiwum]

Tworzymy klasę i taki kod:

import javax.jms.*;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;

public class Main {

    private static String url = ActiveMQConnection.DEFAULT_BROKER_URL; //1
    private static String subject = "test";

    public static void main(String[] args) {
        try {
            ConnectionFactory conncectionFactory = new ActiveMQConnectionFactory(url);
            Connection connection = conncectionFactory.createConnection();
            connection.start();

            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); //2
            Destination destination = session.createQueue(subject);
            MessageProducer producer = session.createProducer(destination);

            TextMessage message = session.createTextMessage("hej to testowa wiadomosc");
            producer.send(message);
	    connection.close();
        } catch (JMSException ex) {
            ex.printStackTrace();
        }
    }
}

(1) ActiveMQConnection.DEFAULT_BROKER_URL oznacza że „message broker” działa na localhost
(2) funcka createSession ma dwa parametry, pierwszy czy połączenie będzie transakcyjne bądź nie, a drugi parametr wskazuje kiedy jest wysyłana wiadomość potwierdzająca otrzymanie komunikatu. Session.AUTO_ACKNOWLEDGE oznacza że potwierdzenie jest wysyłane automatycznie po otrzymaniu komunikatu. Reszta kodu wydaje się oczywista.

Po uruchomieniu aplikacji można wejść w zakładkę Queues, gdzie widać wysłane do komunikaty



a w zakładce Connections widzimy podpiętych klientów.


To wszystko. Przykład jest banalny, ale od czegoś trzeba zacząć 🙂 W następnym wpisie postaram się pokazać przykład wykorzystujący komunikację „Publish and subscribe”, albo „Point to point”. A może oba typy.

Kategorie:JMS Tagi: , ,