JTraining Blog

Share your knowledge.
Tags >> Java EE
svanhugten
svanhugten

When working with JSF 1.x you will eventually find out about some of its annoying features. Such as that it is all about HTTP POST and nothing but HTTP POST. So when working with forms with inputTextArea components you will notice that refreshing or navigating away and then back will leave them blank again. Some of customers I worked for had a problem understand this limitation, because dropdown boxes just worked fine and demanded that the text areas work the same.

I found a small piece of code that will remedy this shortcoming.   

 


Tagged in: Java EE 6 , Java EE , Ajax4JSF , Ajax
svanhugten
svanhugten

... Java is dead! But that's a good thing if you believe the writer of the following article:

http://muckandbrass.com/web/display/~cemerick/2009/10/01/Java+is+dead,+but+you'll+learn+to+love+it

In short he elaborates  on the fact that Java has now become a settled language like C and that any major changes would break more things than that it would change for the better. The world of tomorrow is for languages such as Scala and Groovy. To discuss the subject here, I would like to refer you all to the group discussion.


Tagged in: Java EE 6 , Java EE
svanhugten
svanhugten

De annotaties zijn al een tijdje ingeburgerd in Java en iedereen die ooit met Java 1.5 of hoger heeft gewerkt, zal het vertrouwde @-tje herkennen, maar hoe vaak heb je er nu een zelf gemaakt? Waarschijnlijk nooit, want dat is toch het domein van de Springs, Hibernates en andere frameworks in deze wereld. Hoe gaat het überhaupt in zijn werk? Het is namelijk geen onderdeel van een of ander certificaat.
Op internet zijn wel wat dingen te vinden over hoe annotaties te maken, maar daarbij valt me op dat er nooit wordt ingegaan op zogenaamde runtime annotaties, annotaties die je ook tijdens het runnen van jouw programma kunt gebruiken.

Annotaties zijn in feite niet meer dan interfaces:

public
@interface Ranked {
      String column() default "";
}

Er vallen wel een aantal dingen op; voor het keyword interface staat een @-tje en de property declaratie ziet er heel verschillend uit. Ook ben je wat beperkt in je typekeuze voor een property. Alleen primitieve types, String, Class, annotaties en enums mogen of een 1-dimensionale array hiervan. Geen objecten dus. In de praktijk is dit echter niet echt een belemmering.
Het keyword default geeft, geheel verwacht, een standaard waarde aan de property. Als je dit keyword weglaat, is deze property verplicht om in te vullen.
De overige configuratie kun je op de interface annoteren en zal ik even de vier nuttigste opties doornemen:

@Retention:
Dit geeft aan wanneer een annotatie beschikbaar is op de class. Dit kan zijn alleen tijdens build-time, tijdens compile-time of tijdens runtime. Zie de enum RetentionPolicy.

@Target
Dit geeft aan waar de annotatie geldig is, bv. op types, fields of methods. Zie de enum ElementType.

@Documented
Dit geeft aan of de annotatie ook wordt meegenomen met de Javadoc.

@Inherited
Dit geeft aan of de annotatie ook wordt doorgegeven via inheritance.

Onze annotatie zie er na configuratie er als volgt uit:

@Retention(value=RetentionPolicy.RUNTIME)
@Target(value={ElementType.TYPE})
@Documented
public @interface Ranked {

}

Dus kunnen we deze annotatie tijdens runtime nog steeds gebruiken en mag deze alleen op classes worden gebruikt. De @Documented spreekt vanzelf.
Nu is de annotatie klaar voor gebruik op de bekend manier:

/*
* Deze class is geranked.
*/
@Ranked
public class Product {

}
 
Nu moeten we ook nog wat met deze property gaan doen, want ook al lijkt Spring soms magisch, het werkt niet vanzelf. Onze magie zit bijvoorbeeld in de DAO, waar we entiteiten met @Ranked automatisch sorteren. (Ja, ik weet dat dit ook kan met @Sort kan)

if (persistentClass.isAnnotationPresent(Ranked.class)) {
            return findByCriteriaOrdered(Order.desc(RANK));
}

Waar het hier om gaat is de method isAnnotationPresent van de class Class. Deze kijkt of een annotatie tijdens runtime (vandaar de RetentionPolicy) in de class aanwezig is. Als dat zo is, kun je daarmee iets doen, zoals hier gebeurd.


Tagged in: Reflection , Java SE , Java EE 6 , Java EE
sneake75@hotmail.com
sneake75@hotmail.com Introduction:

In this part we are going to show how to implement some of the famous replacement algorithms as we mentioned in part 1, the code in this article is just for demonstration purpose which means you will have to do some extra effort if you want to make use of it in your application (if you are going to build your own implementation and wont use any caching frameworks)

The Leftover policy:

After programmer 1 read the article he proceeded to review the comments on this article, one of these comments were talking about leftover policy, which is named “Random Cache”

Random Cache:





Tagged in: Java EE , Caching , Algorithms
svanhugten
svanhugten

 

Het uploaden van bestanden is vaak een niet-triviale taak. Eerst moet je het bestand worden gevalideerd op type en grootte, naar een tijdelijke bestemming worden gestreamed en daarna gekopieerd, wat nu al simpeler klinkt dan het is als je het zelf moet doen.
Met RichFaces wordt het echter een stuk simpeler, een oplossing die ik jullie niet wilde onthouden.

De component:

Met de <rich:fileUpload> tag plaats je de component. In mijn geval ziet het er als volgt uit:

<rich:fileUpload maxFilesQuantity="1"
            immediateUpload="true"  onsizerejected=
"alert('Uw bestand mag niet groter dan 1000KB zijn');"
            ontyperejected=
"alert('Alleen *.jpg, *.gif, *.png en *.bmp bestanden zijn toegestaan als plaatje');"
            acceptedTypes=
"jpg, gif, png, bmp"
            fileUploadListener="#{bean.upload}">
</rich:fileUpload>


Dit creëert een upload-component dat één plaatje accepteert en het meteen upload na het selecteren. Als het groter is dan 1000KB (te configureren als maxRequestSize init-param bij het rich-faces filter in web.xml) of als niet voldoet aan de bestandtype-eis, dan geeft dit component netjes een melding. De listener verwijst naar een specifiek event in de achterliggende bean.

public void upload(UploadEvent event) throws IOException {
        UploadItem item = event.getUploadItem();
        String filePath = //path waar het bestand naar toe moet

        File file = new File(filePath);
        file.createNewFile();
        FileOutputStream fos = new FileOutputStream(file);
        // In de web.xml is ook weer configureren of er  tijdelijke bestanden worden
        // gemaakt of dat alleen het geheugen wordt gebruikt. Standaard wordt er
        // gebruik gemaakt van tijdelijke bestanden.
        //<init-param>
        //   <param-name>createTempFiles</param-name>
        //   <param-value>true</param-value>
        //</init-param>   
        if (item.isTempFile()) {
            FileInputStream fis = new FileInputStream(item.getFile());
            IOUtils.write(IOUtils.toByteArray(fis), fos);
            fis.close();
        } else {
            IOUtils.write(item.getData(), fos);
        }
        fos.close();
}


Merk op dat ik bij deze code ook de IOUtils uit Apache Commons gebruik om de bestandsafhandeling aanzienlijk te vereenvoudigen.
Hiermee is het bestand geupload, inclusief nette afhandeling van eventuele fouten. Bedankt RichFaces!











































Tagged in: RichFaces , Java SE , Java EE , Ajax4JSF
svanhugten
svanhugten

Sinds een tijdje (ergens rond Eclipse 3.3/3.4) treedt er een lastig probleem op in de volgende situatie:

 

- Je hebt een web applicatie project in Eclipse
- Je bouwt de war met Maven
- Je deployed het binnen Eclipse met de standaard Tomcat-plugin


Tagged in: Web applications , Maven , Java SE , Java EE
svanhugten
svanhugten ‘Nee' is mijn eerste antwoord en waarom wil ik graag met jullie delen. Een typische Java bean ziet er als volgt uit:

public class BankAccount {

private long number;

private Customer owner;

private double balance;

public long getNumber() {

return this.number;

}

public void setNumber(long number) {

this.number = number;

}

Etc...


}


Niet veel mis mee zou je zeggen. Op zich is hier ook mee te werken, maar is een goede Object Oriented class? Je bent geneigd om ‘Ja' te antwoorden, maar als je de class eens goed bekijkt, begint er wat te kriebelen. Houdt deze class zit netjes aan het encapsulation-principe? De class members zijn private gedeclareerd, maar door automatisch getter/setter-paren te maken, heeft iemand die gebruik maakt van de class toch de volledige controle over de interne staat van het object. Bovendien kun je op deze manier nooit de staat van jouw object garanderen. Op ieder moment kan iemand in de code de inhoud van jouw object veranderen!

Om de staat van jouw object te garanderen, kun je een heel logische manier te gebruiken om dit af te dwingen; de constructor. Door af te stappen van het gebruik van de default constructor en dan vervolgens de class member met setters te vullen, kun je afdwingen dat een object wordt aangemaakt op de manier zoals jij het bedoelt hebt.

Een BankAccount mag bijvoorbeeld niet zonder owner worden aangemaakt, noch mag het saldo bij opening negatief zijn. Volgens de standaard manier is dit gemakkelijk wel eens te vergeten.

BankAccount newAcc = new BankAccount();

newAcc.setNumber(1023L);

newAcc.setBalance(-100.00);

...wat business logic met de account

// Oeps, customer vergeten


Zo krijg je dus een hoop ongewenste situaties. Beter is dus:

BankAccount newAcc = new BankAccount(1023L, customer, 100L);


Waarbij de constructor er als volgt uitziet:

public BankAccount(long number, Customer owner, double balance) {

if (customer == null) {

throw new IllegalStateException("Customer can't be NULL");

}


if (balance < 0) {

throw new IllegalStateException("Opening balance can't be negative");

}


this.number = number;

this.owner = owner;

this.balance = balance;

}


Zo ben je er altijd van verzekerd dat een BankAccount correct wordt geconstrueerd. Bovendien geeft dit een single point of construction, want zonder setters kan de state van dit object niet meer veranderen. Eenmaal correct gemaakt, betekend dat een object altijd valide is binnen het programma. Overigens kan de validatie logic een stuk korter met behulp van Apache Commons. Dan wordt de constructor als volgt:

public BankAccount(long number, Customer owner, double balance) {
Validate.notNull(customer, "Customer can't be NULL");

Validate.isTrue(balance > 0, "Opening balance can't be negative");

this.number = number;

this.owner = owner;

this.balance = balance;

}


Natuurlijk is het niet zo dat je nooit meer de staat van een object mag veranderen volgens deze manier, alleen als je dit doet, moet je de verandering controleren of het object in een valide staat blijft. Bijvoorbeeld, een bankrekeningsaldo kan veranderen:

public void changeBalance(double change) {


this.balance += change;


// Staat controleren

if (this.balance < 0 and !this.owner.canHaveNegativeBalance()) {

// Eigenaar mag niet rood staan, transactie terugdraaien

this.balance -= change;

}


}


Dit kan natuurlijk ook met een setter, maar naast een betere beschrijving van het gedrag van deze methode heeft dit ook het vaak vergeten voordeel van validatie op het object zelf. Vooral omdat de setter vaak wordt gegenereerd, wordt de validatie logica vaak in de business logic gedaan, wat fouten en duplicate code in de hand werkt. Een correcte class ziet er dus als volgt uit:

public class BankAccount {

private long number;

private Customer owner;

private double balance;

public BankAccount(long number, Customer owner, long balance) {


Validate.notNull(customer, "Customer can't be NULL");

Validate.isTrue(balance > 0, "Opening balance can't be negative");

this.number = number;

this.owner = owner;

this.balance = balance;

}

public long number() {

return number;

}


public Customer owner() {

return owner;

}

public BigDecimal balance() {

return balance;

}

public void changeBalance(double change) {

this.balance += change;


// Staat controleren

if (this.balance < 0 and !this.owner.canHaveNegativeBalance()) {

// Eigenaar mag niet rood staan, transactie terugdraaien

this.balance -= change;

}

}


}


Een laatste punt dat ik wil aanstippen, is het gebruik maken van de defensive copy techniek. Een goed voorbeeld is een getter die een collection teruggeeft:

public List<Customer> customers() {

return this.customers;

}


De bedoeling van deze method is de informatie in customers collection teruggeven en niet om hem te kunnen veranderen. Toch kan dit op deze manier, immers is een collection niet immutable en geef je het object zelf terug, dus dit is het gevolg:

List<Customers> stolenCustomers = branch.customers();

system.out.println(branch.customers().size()); //bv. 5

stolenCustomers.add(new Customer("Alan", "Johnston", etc...));

system.out.println(branch.customers().size()); //6!


Onbedoeld heeft een filiaal er dus een klant bij gekregen, zonder dat zelf te willen. Om dit te voorkomen moet er een defensief kopie worden aangemaakt, zodat de echte class member niet kan worden veranderd.

public List<Customer> customers() {

return new ArrayList(this.customers);

}


Hierdoor krijgt je bij het opvragen van de customers collection een kopie van de lijst in plaats van het originele object. Object georiënteerd programmeren klinkt tegenwoordig zo vanzelfsprekend, maar zoals je ziet gaat het gemakkelijk zelfs al op model niveau fout. Dat het werken vanuit een groeiende servicegeoriënteerde wereld ook niet echt netjes programmeren in de hand werkt, is weer een andere discussie...

Nuttige bronnen:

Validation belongs in a Model Object
Validate state with class invariants
Self-encapsulate fields
Constructors in general
Avoid JavaBeans style of construction 

Tagged in: Java SE , Java EE 6 , Java EE
svanhugten
svanhugten

Probleem: door het werken met een technologie als JSF vertelt het adres van de pagina niet altijd de juiste staat van de pagina. Bijvoorbeeld, bij het bekijken van een product detailpagina kan het adres nog steeds www.site.nl/producten/details.jsf zijn, of nog erger, /producten/overzicht.jsf! Omdat de identificatie-informatie van het product wordt bijgehouden in een page/business bean, hoef je als programmeur dit niet door te geven via de adresbalk. Dat is veilig, maar wat als de bezoeker nu eens zo geïnteresseerd is geraakt in het product, dat hij of zij dit later nog eens wil bekijken? De volgende keer dat de bezoeker de bookmark bezoekt, krijgt hij in het gunstigste geval een foutmelding te zien dat er geen product kan worden gevonden. De session-scoped bean is inmiddels al weer opgeruimd en dat ID zien we nooit meer terug. Gevolg: een teleurgestelde klant.
Je kunt natuurlijk zelf bookmark knoppen maken of accounts met wishlists, maar het kan makkelijker met PrettyFaces. PrettyFaces vervangt in principe je gehele JSF navigatiemodel met zijn eigen configuratie waarmee je bookmarkable URLs kunt produceren. /producten/details.jsf met in ProductDetailPB.java het ID op 1234 wordt dan door PrettyFaces omgeschreven in /producten/details/1234. Als vervolgens naar deze URL wordt gegaan, vertaalt PrettyFaces het intern naar het adres /producten/details.jsf en zet 1234 als waarde van ID in ProductDetailPB.java.

Het toevoegen van PrettyFaces aan jouw applicatie is niet moeilijker dan een gemiddeld ander JSF framework. Een filterconfiguratie toevoegen aan jouw web.xml is voldoende:

<filter>
    <filter-name>Pretty Filter</filter-name>
    <filter-class>com.ocpsoft.pretty.PrettyFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>Pretty Filter</filter-name>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>


Vervolgens zet je jouw navigation cases in pretty-config.xml in plaats van de normale faces-config. Een voorbeeld van een normale navigation case in PrettyFaces:

 <url-mapping id="home">
  <pattern>/home</pattern>
  <view-id>/pages/home/home.jspx</view-id>
 </url-mapping>

Dit staat dus gelijk aan:

 <navigation-rule>
  <from-view-id>*</from-view-id>
  <navigation-case>
   <from-outcome>home</from-outcome>
   <to-view-id>/pages/home/home.jspx </to-view-id>
  </navigation-case>
 </navigation-rule>

Als dus naar /home wordt gesurft, herschrijft PrettyFaces intern het adres naar /pages/home/home.jspx. De gebruiker ziet hier niets van. Om deze links op te nemen in de pagina, heeft PrettyFaces ook een speciaal link-component gemaakt.

<pretty:link mappingId="home">Home</pretty:link>

Dit produceert dus een link naar /home. Het mappingId attribuut correspondeert dan weer met het id attribuut in de url-mapping. Een gewone html-link werkt overigens ook prima.
De grote kracht van PrettyFaces zit hem eigenlijk dat er bij een URL-mapping actions kunnen worden uitgevoerd voordat de pagina wordt getoond. Om terug te komen op mijn voorbeeld van de product detail-pagina; voor het gewenste effect zou ik het zo maken.

<url-mapping id="viewProductDetails">                       <pattern>/producten/details/#{productDetailPB.productID}</pattern>
<view-id>/producten/details.jsf</view-id>
<action>#{productDetailPB.loadItem}</action>
</url-mapping>

Door naar /producten/details/1234 te gaan, wordt productID in productDetailPB op 1234 gezet. De action-tags zorgen ervoor dat loadItem in de pagebean wordt uitgevoerd. Een bezoeker kan zo de pagina bookmarken en de volgende keer naar precies dezelfde pagina terugkeren, zonder de maker hiervoor het programma hoefde om te gooien. Isn't that pretty?


Tagged in: Java SE , Java EE
svanhugten
svanhugten Okee, ik moet toegeven; Spring is natuurlijk ook ergens wel debet aan het hele ontstaan van de XML-hell, maar sinds versie 2.5 maken ze hier een einde aan met nieuwe annotaties. Hiervan wil ik er een aantal van gaan bespreken, omdat deze niet allemaal even bekend zijn.

Niet zo heel lang geleden zag een typische bean-declaratie er zo uit:

<bean id="vbBean" class="com.acme.web.pagebean.VbBean" scope="session">
         <property name="otherService" ref="otherServiceBean"/>
</bean>

In de VbBean klasse stond dan een property ‘otherService' met een getter/setter paar voor de injection. Vooral de verplichte getter/setter paartjes zorgden voor een flinke vervuiling van de code zonder verder van nut te zijn. Daarnaast kon de applicationContext.xml naar verloop van tijd erg ondoorzichtig worden met allerlei imports naar allerlei andere configuratiebestanden met allemaal hun eigen berg beans en dan vergeten we nog even voor het gemaakt dat je waarschijnlijk ook nog meerdere configuraties voor andere omgevingen bijhoudt.
Dit is allemaal niet meer nodig met de nieuwe annotaties. Als er nu injection nodig is, kan dit direct op de property worden geannoteerd.

Public class VbBean {

         @Resource
         Private OtherService otherService;

            ...overige code...
}


Hoe weet Spring nu wat hiermee wordt bedoeld? Door de @Service annotatie op de implementatieklasse van de OtherService aan te brengen. Dat ziet er zo uit.

@Service
Public class OtherServiceImpl implements OtherService {
}


Voor de interface is geen speciale annotatie nodig. Door deze annotatie weet Spring dat OtherServiceImpl een implementatie is van de gezochte OtherService en inject deze in VbBean, zonder getter of setter! Niet alleen lokale, maar ook beans uit een JNDI context kunnen zo worden geïnjecteerd.
Als er meerdere implementaties beschikbaar zijn, kan de annotatie worden uitgebreid zodat duidelijk wordt welke implementatie er nodig is.

Public class VbBean {

            @Resource(name="OtherServiceImpl1")
            Private OtherService otherService;

            ...overige code...
}


@Service("OtherServiceImpl1")
Public class OtherServiceImpl implements OtherService {
}


Als VbBean nu een PageBean/BusinessBean is, kan Spring ook hierbij helpen met de configuratie. Twee eenvoudige annotaties zorgen ervoor dat de VbBean gebruik kan worden:

@Component("vbBean")
@Scope("request")
Public class VbBean {

            @Resource(name="OtherServiceImpl1")
            Private OtherService otherService;

            ...overige code...
}


Vervolgens kan deze bean worden benaderd via een EL-expressie, bijvoorbeeld met #{vbBean.someMethod}. Natuurlijk is er nog wel iets van configuratie nodig. Spring weet niet vanzelf wat zijn context is, maar gelukkig is dit ook zo eenvoudig mogelijk gehouden.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <!-- We use annotation for configuring the beans and injecting dependencies-->
    <context:annotation-config/>

    <!-- we  scan the beans in the following packages -->
    <context:component-scan base-package="com.acme.web"/>

</beans>

Dit is alles! Het base-package attribuut geeft aan welke package er gescand moet worden voor componenten om toe te voegen aan de Spring context. Alle beans onder com.acme.web die geannoteerd zijn met @Component (@Repository, @Service of @Controller zijn afgeleid van Component) worden meegenomen en zijn beschikbaar binnen de context onder hun gegeven naam.
Een stuk minder werk zou ik zeggen. Op deze manier kan (bijna) elke bean worden geconfigureerd en ook Aspect georiënteerde logging wordt ondersteund.


Tagged in: Spring , Java SE , Java EE
svanhugten
svanhugten Van de week was ik weer eens bezig met een JSF pagina en er moest iets relatief simpels gebeuren; de gebruiker moest een ‘Weet u dit zeker'-schermpje krijgen als hij/zij iets probeerde te verwijderen. Geduldig zocht ik door alle componenten die ik tot mijn beschikking had en kwam tot mijn schrik tot de conclusie dat er geen confirmation dialog component was in alle component sets die ik gebruikte. JSF Core, MyFaces, RichFaces, Facelets, geen enkele verwijzing naar een confirmation box of iets dat er op leek.
Even googlen geeft wel wat opties zoals deze, maar ik wou alleen het bekende javascript-venstertje laten zien en niet een berg code in mijn pagina's op te nemen of een compleet nieuw component te maken. Het is ten slotte een gewoon stukje javascript, kan dat niet anders?
Natuurlijk wel! De oplossing is bijna te simpel voor woorden:

<h:commandButton action="#{bean.action}" onclick="if (!confirm('Weet u dit zeker?')) return false;" />

De oplossing zit hem in het ‘if (expression is false) return false'-gedeelte. Door de ‘return false' staakt het script zijn werking en wordt de action niet uitgevoerd. Dit stukje code is zelfs nog volledig aan te passen voor internationale toepassingen met i18n bundles.

<h:commandButton action="#{bean.action}" onclick="if (!confirm('#{labels['message.confirm']}')) return false;" />

Voordelen van deze aanpak is dat het zeer weinig code is, die bovendien ook nog voor elke action bruikbaar is. Nadelen hieraan is dat het gevaar op loer ligt dat, als je dit scriptje vaak gebruikt, de code rommelig kan worden door het copy-pasten (Ik weet niet zeker of de labels het ook nog doen als je de code externaliseert). Ook is de dialog box niet te skinnen, wat natuurlijk op te lossen valt door de code/het component van de eerder gelinkte website te gebruiken.
Veel succes ermee!

Tagged in: RichFaces , JSF , Java SE , Java EE , Ajax4JSF
« StartPrev12NextEnd »

Tags:

Sponsers