Česky   |  Deutsch   |  English   |  Español   |  Français   |  Indonesia   |  日本語   |  한글   |  Polski   |  Português (BR)   |  Türkçe   |  中文   |  正體中文   |  Your Language  
PlanetNetbeans
Planeta NetBeans jest agregatorem treści związanych z NetBeans IDE pochodzących z całej blogosfery.
Kanały
[RSS 1.0 Feed] [RSS 2.0 Feed]
[FOAF Subscriptions] [OPML Subscriptions]
Blogujesz na tematy związane z NetBeans? Dodaj swój blog do PlanetNetBeans!
Subskrypcja kanałów

Powered by:    Planet

Last updated:
July 05, 2008 10:16 PM
All times are UTC

sponsored by Sun Microsystems

visit NetBeans website
Jacek Laskowski - Notatnik Projektanta Java EE - July 02, 2008 11:18 PM
Umiędzynarodowienie w JBoss Seam, NetCAT 6.5 oraz nowa grupa oferty-pracy-java

W końcu natrafiłem na notkę odnośnie roli seam.properties w aplikacji w książce Beginning JBoss® Seam: From Novice to Professional wydawnictwa Apress oraz gdzieś w Sieci. Cała magia seam.properties to przede wszystkim oznaczenie archiwum WAR lub JAR jako zawierające komponenty seamowe i stąd konieczność umieszczenia go w /WEB-INF/classes w aplikacji webowej, aby Seam zechciał rozważyć przeszukiwanie aplikacji w celu "namierzenia" klas oznaczonych adnotacją @Name. Plik seam.properties może być całkowicie pusty - wystarczy jego istnienie. Trudno jednak zrozumieć, dlaczego umieszczenie definicji komponentów w components.xml działa, a już przeszukiwanie ich w archiwum nie. Czyż Seam nie dowiedział się właśnie poprzez plik components.xml, że ma do czynienia z aplikacją seamową?! Na chwilę obecną nie zamierzam zaglądać do kodu źródłowego, ale pewnie tam należałoby szukać odpowiedzi. Chętni?! ;-)

Dzisiaj na tapetę poszedł temat umiędzynarodowienia aplikacji seamowej (przypomina mi się temat Umiędzynarodowienie w Apache Wicket i trochę ckni mi się do Wicketa i możliwości jego uruchomienia na OSGi). Temat umiędzynarodowienia aplikacji korzystającej z JavaServer Faces był już przeze mnie przedstawiany w artykułach requiredMessage i resource-bundle - udoskonalona kontrola komunikatów w JSF 1.2, Uruchamiamy pierwszą aplikację w technologii JavaServer Faces, Tworzenie aplikacji z JavaServer Faces, Apache Maven i Apache Geronimo czy JavaServer Faces i Spring Framework w parze z Apache Maven i Apache Geronimo. Wszystkie dotykają tematu użycia message-bundle w faces-config.xml, kontrolki <f:loadBundle> na stronie JSF, gdzie korzysta się z tłumaczeń oraz wskazanie na niego z danego pliku tłumaczeń - #{komunikaty['wprowadz_imie']}. Jest tego trochę do zapamiętania, co Seam zauważalnie skrócił.

Pierwsza różnica między "czystą" (nieseamową) aplikacją JSF a opartą o Seama to założenie, że wszystkie pliki properties z tłumaczeniami składają się na jedną mapę messages klucz-tłumaczenie. W przypadku JSF mamy mapę per plik tłumaczeń. Kolejna zmiana to zniesienie obowiązku definiowania plików tłumaczeń w faces-config.xml - obowiązkowym pliku konfiguracyjnym każdej aplikacji opartej o JSF. I na koniec podsumowania różnic, Seam znosi obowiązek deklarowania użycia pliku tłumaczeń za pomocą <f:loadBundle>. Z Seamem wystarczy utworzyć pojedyńczy plik messages.properties dla wybranych języków i użyć konstrukcji #{messages['klucz']} w dowolnym miejscu strony JSF. Oczywiście istnieje możliwość zdefiniowania wielu plików tłumaczeń. "Gdzie?" - zapytasz. Oczywiście w opcjonalnym components.xml, który wraz z kilkoma innymi opcjonalnymi plikami xmlowymi przejął rolę obowiązkowego faces-config.xml w JSF (podkreślam użycie słów opcjonalny i obowiązkowy).

Więcej informacji ze źródła o umiędzynarodowieniu aplikacji seamowych w dokumentacji Seama - Chapter 15. Internationalization, localization and themes, a w szczególności 15.3.1. Defining labels. Podczas poznawania mechanizmu tłumaczeń w Seamie brakowało mi wiedzy, którą ostatecznie udało mi się znaleść na forum Seam Users w wątku Including a resource bundle not called messages*.

Umiędzynarodowienie mojej aplikacji seamowej, którą rozwijam od kilku dni, rozpocząłem od zmian w pliku components.xml, gdzie wskażę pliki tłumaczeń.

 <?xml version="1.0" encoding="UTF-8"?>
<components
xmlns="http://jboss.com/products/seam/components"
xmlns:core="http://jboss.com/products/seam/core"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.0.xsd
http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.0.xsd">
<core:init debug="true" />
<core:resource-loader>
<core:bundle-names>
<value>komunikaty</value>
<value>messages</value>
</core:bundle-names>
</core:resource-loader>
</components>
Przypomnę, że jest to krok opcjonalny i domyślnie Seam poszukuje pliku messages.properties dla danego języka, np. messages_pl.properties dla polskiego. Plik musi znajdować się w ścieżce klas aplikacji, co w moim przypadku aplikacji webowej sprowadziło się do umieszczenia go w katalogu /WEB-INF/classes. W powyższej konfiguracji w components.xml dodałem również użycie pliku komunikaty_pl.properties.

Opcjonalnie zdefiniowałem domyślny język aplikacji (polski) i inne wspierane języki (polski) w faces-config.xml:
 <?xml version='1.0' encoding='UTF-8'?>
<faces-config version="1.2"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
<application>
<locale-config>
<default-locale>pl</default-locale>
<supported-locale>pl</supported-locale>
</locale-config>
<view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
</application>
</faces-config>
W ten sposób zagwarantowałem, że jedynym słusznym językiem w aplikacji będzie polski. Wyboru nie ma.

Zawartość pliku messages_pl.properties:
 kategoria.tytul=Administracja kategoriami
oraz komunikaty_pl.properties:
 kategoria.nazwa=Nazwa
kategoria.opis=Opis
Oba pliki muszą znaleźć się na ścieżce klas, np. /WEB-INF/classes w ramach archiwum war.

Mając tak zdefiniowane pliki tłumaczeń zmodyfikowałem stronę kategoria.xhtml:
 <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core">
<head>
<title>#{messages['kategoria.tytul']}</title>
</head>
<body>
<f:view>
<h:form>
<s:validateAll>
<h:panelGrid columns="2">
#{messages['kategoria.nazwa']}: <h:inputText value="#{kategoria.nazwa}" required="true" />
#{messages['kategoria.opis']}: <h:inputText value="#{kategoria.opis}" required="true" />
</h:panelGrid>
</s:validateAll>
<h:messages />
<h:commandButton value="Dodaj" action="#{kategoriaAgent.dodaj}" />
<br />
<h:outputText value="Brak kategorii" rendered="#{kategorie.rowCount==0}" />
<h:dataTable var="ktgria" value="#{kategorie}" rendered="#{kategorie.rowCount>0}">
<h:column>
<f:facet name="header">
<h:outputText value="Nazwa" />
</f:facet>
<h:commandLink value="#{ktgria.nazwa}" action="#{kategoriaAgent.wybierz}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Opis" />
</f:facet>
<h:outputText value="#{ktgria.opis}" />
</h:column>
<h:column>
<h:commandButton value="Delete" action="#{kategoriaAgent.skasuj}" />
</h:column>
</h:dataTable>
<h3><h:outputText value="#{kategoriaWybrana.nazwa}" /></h3>
<div><h:outputText value="#{kategoriaWybrana.opis}" /></div>
</h:form>
</f:view>
</body>
</html>
Na uwagę zasługuje użycie #{messages['kategoria.tytul']} w tytule poza sekcją <f:view> oraz #{messages['kategoria.nazwa']} i #{messages['kategoria.opis']} w <h:panelGrid>. Przypomnę, że wszystkie komunikaty trafiają do jednej zbiorczej mapy - messages, więc należy zagwarantować unikalność zawartych w niej kluczy tłumaczeń, np. poprzedzając nazwą strony, w której się znajdują.

Uruchomienie strony kategoria.xhtml, to jak można się domyśleć pojawienie się napisów z plików tłumaczeń. Proste, nieprawdaż?

Na zakończenie kilka słów spoza obszaru Seama. Właśnie pojawiło się zaproszenie do NetBeans IDE 6.5 Community Acceptance Testing program (NetCAT). W programie NetCAT miałem już przyjemność uczestniczyć w poprzednich edycjach i wiele mogłem się w nich nauczyć samego NetBeansa, ale również i technologiach Korporacyjnej Javy recenzując artykuły o nich i samemu sprawdzając ich działanie w NB. I tym razem nie mogłem sobie odpuścić zgłoszenia się do programu, szczególnie, że z tą wersją rokuję pewne nadzieje w kontekście znaczącego usprawnienia we wsparciu dwóch serwerów aplikacyjnych IBM WebSphere Application Server 6.1 oraz Apache Geronimo. Może się do czegoś przydam i sprawię, aby pracowało się przyjmniej z NetBeans 6.5? ;-) A Ty? Każdy może się przyłączyć, więc szkoda czasu na zbędne zastanawianie się - lepiej ten czas przeznaczyć na poznawanie błędów^H^H^Hfunkcjonalności NB 6.5.

Kilka dni temu Michał B. podjął się tematu wyjaśnienia odmiany słowa Java i jego pisowni w komentarzu do W sprawie Recenzja książki "Hibernate. Od Nowicjusza do Profesjonalisty". Odpowiedź od jego znajomego filologa trochę mnie zaskoczyła:

"wyraz 'Java' proponuję używać tylko w formie mianownikowej i odmieniać tylko wyraz 'język' - czyli np. języka Java, o/w języku Java.
To zapewni jednoznaczność terminologii w tekstach - oczywiście mówiąc nie trzymałbym się kurczowo takiej opcji - tu może być sama [dżawa] a formy [w dżawie] itp. wystarczą (o czym sam doskonale wiesz:)) "


Zaskoczeni podobnie jak ja? Jestem zdania, że można odmieniać słowo Java w dowolnym zestawieniu, czyli o javie, z javą i bez javy (chociaż to ostatnie nie przechodzi mi jakoś przez gardło ;-))

I na koniec informacja o dedykowanej grupie oferty-pracy-java, gdzie zamieszczane są wyłącznie oferty dotyczące obszaru programowania, testowania czy projektowania z użyciem technologii javowych z uwzględnieniem widełek płacowych. Jeśli uważasz, że jest coś więcej, co powinno pojawiać się w każdym ogłoszeniu o pracę, zapraszam do udziału w grupie i wprowadzenia stosownych zmian. Każdy ma prawo głosu, a celem jest stworzenie miejsca, w którym oferty będą tak profesjonalne, jak osoby, które z nich zamierzają skorzystać. My jako owa wykwalifikowana kadra możemy wpłynąć na kształt ofert i korzystania z nich dla dobra własnego. W ten sposób z pewnością uda nam się wypracować nowy styl pisania ofert z właściwymi wymaganiami, widełkami płacowymi, dodatkami, itp. Grupa jest moderowana i przy rejestracji należy określić swoją rolę - oferent/rekruter vs zainteresowany (wyłącznie dla celów...hmm...nie mam pojęcia jakich, ale pomyślałem, że dobrze wiedzieć jakie są proporcje). Dyskusje o uszczegółówienie ofert jak najbardziej wskazane. Grupa jest publiczna. Archiwum do przeglądania przez każdego, ale jedynie członkowie mogą dyskutować na grupie (po zatwierdzeniu posta przez moderatora). Sądzę, że warunki są idealne do wymagań obu stron - firm rekrutacyjnych i kadry pracowniczej. Promocja siebie jak najbardziej wskazana przez wysłanie CV na grupę. Wszystko, co sprawi, że będzie można znaleźć swoją wymarzoną pracę łatwiej mile widziane. Zapisz się i działaj!

Pytanie konkursowe: Jak nazywa się mapa tłumaczeń w Seamie? I takie bardzo zaawansowane: W jaki sposób (gdzie i jak) definiuje się wiele plików tłumaczeń w Seamie?

Marek Kliś - różności okołojavowe i nie tylko - June 29, 2008 05:17 PM
NetBeans + Ecplise = ...

W sobotę (28.08.2008) miałem okazję uczestniczyć w Ecplise DemoCamps w Krakowie. Spotkanie zaliczam do udanych. W drodze powrotnej przypomniał mi się niedawny wpis na blogu Geertjan Wielengi opisujący jak uruchomić aplikację napisaną z wykorzystaniem NetBeans Platform z Eclipsa.
Jako, że ostatnio miałem trochę do czynienia z bardzo fajną biblioteką Visual Library, która wchodzi w skład platformy NetBeans, pomyślałem, że może by spróbować napisać prosty programik w Eclipsie wykorzystujący tą bibliotekę.
Ściągnąłem Visual Library, odpaliłem Eclipsa i zabrałem się do pracy. Okazało się, że tej pracy nie było dużo (wręcz prawie w ogóle).
Po pierwsze stworzyłem panel, na którym miał wylądować edytor graficzny.


package pl.marekklis.graph;

import java.awt.BorderLayout;
import java.awt.Dimension;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import org.netbeans.api.visual.graph.GraphScene;

public class GraphTest extends JPanel{

public static void main(String[] args) {
JFrame frame = new JFrame("Graph test");
frame.setMinimumSize(new Dimension(400,300));
frame.setSize(400, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new GraphTest());
frame.pack();
frame.setVisible(true);
}

public GraphTest() {
initComponents();
}

private void initComponents(){
setLayout(new BorderLayout());
JScrollPane scrollPane = new JScrollPane();
add(scrollPane,BorderLayout.CENTER);
GraphScene scene = new GraphSceneImpl();
scrollPane.setViewportView(scene.createView());
add(scene.createSatelliteView(),BorderLayout.WEST);
}

}


Po drugie stworzyłem implementacje GraphScene.


package pl.marekklis.graph;

import java.awt.Point;

import org.netbeans.api.visual.action.ActionFactory;
import org.netbeans.api.visual.action.ConnectProvider;
import org.netbeans.api.visual.action.ConnectorState;
import org.netbeans.api.visual.anchor.AnchorFactory;
import org.netbeans.api.visual.anchor.AnchorShape;
import org.netbeans.api.visual.graph.GraphScene;
import org.netbeans.api.visual.widget.ConnectionWidget;
import org.netbeans.api.visual.widget.LayerWidget;
import org.netbeans.api.visual.widget.Scene;
import org.netbeans.api.visual.widget.Widget;
import org.netbeans.api.visual.widget.general.IconNodeWidget;
import org.openide.util.Utilities;

public class GraphSceneImpl extends GraphScene {

private LayerWidget mainLayer;
private LayerWidget connectionLayer;
private LayerWidget interactionLayer;

public GraphSceneImpl() {
mainLayer = new LayerWidget(this);
connectionLayer = new LayerWidget(this);
interactionLayer = new LayerWidget(this);
addChild(mainLayer);
addChild(connectionLayer);
addChild(interactionLayer);
Widget w1 = addNode("1. węzeł");
w1.setPreferredLocation(new Point(10, 100));
Widget w2 = addNode("2. węzeł");
w2.setPreferredLocation(new Point(100, 250));
Widget w3 = addNode("Jakiś kolejny węzeł");
w3.setPreferredLocation(new Point(250, 250));
Widget w4 = addNode("Jakiś kolejny węzeł");
w4.setPreferredLocation(new Point(250, 350));
getActions().addAction(ActionFactory.createZoomAction());
}

@Override
protected Widget attachNodeWidget(String arg0) {
IconNodeWidget widget = new IconNodeWidget(this);
if (arg0.startsWith("1")) {
widget.setImage(Utilities.loadImage("pl/marekklis/graph/
resources/gr01.png"));
} else if (arg0.startsWith("2")) {
widget.setImage(Utilities.loadImage("pl/marekklis/graph/
resources/gr02.png"));
} else {
widget.setImage(Utilities.loadImage("pl/marekklis/graph/
resources/gr03.png"));
}
widget.getActions().addAction(
ActionFactory.createExtendedConnectAction(
connectionLayer,new MyConnectProvider()));
widget.getActions().addAction(
ActionFactory.createAlignWithMoveAction(
mainLayer, interactionLayer,
ActionFactory.createDefaultAlignWithMoveDecorator()));
widget.setLabel(arg0);
mainLayer.addChild(widget);
return widget;
}

@Override
protected Widget attachEdgeWidget(String arg0) {
return null;
}

@Override
protected void attachEdgeSourceAnchor(
String arg0, String arg1, String arg2) {
}

@Override
protected void attachEdgeTargetAnchor(
String arg0, String arg1, String arg2) {
}

private class MyConnectProvider implements ConnectProvider {

public boolean isSourceWidget(Widget source) {
return source instanceof IconNodeWidget && source != null
? true : false;
}

public ConnectorState isTargetWidget(Widget src, Widget trg) {
return src != trg && trg instanceof IconNodeWidget ?
ConnectorState.ACCEPT : ConnectorState.REJECT;
}

public boolean hasCustomTargetWidgetResolver(Scene arg0) {
return false;
}

public Widget resolveTargetWidget(Scene arg0, Point arg1) {
return null;
}

public void createConnection(Widget source, Widget target) {
ConnectionWidget conn = new ConnectionWidget(
GraphSceneImpl.this);
conn.setTargetAnchorShape(AnchorShape.TRIANGLE_FILLED);
conn.setTargetAnchor(AnchorFactory.
createRectangularAnchor(target));
conn.setSourceAnchor(AnchorFactory.
createRectangularAnchor(source));
connectionLayer.addChild(conn);
}
}
}


I oto efekt:


W naszym okienku mamy działający przykład wykorzystujący Visual Library.