Internett: www.wis.no E-post: wis@wis.no
Tlf: 7245 0190 Fax: 7245 0191

Startsiden | Produkter | Drift | Markedsføring | Ta kontakt | Gå til
Søk:
Logg innLogg inn 

WIS blogg


BeanModel generering med AutoBean støtte
Av: Stig Runar Vangen Mandag 07.02.2011 (15:11)

Vi har i det siste jobbet med å konvertere vår under utvikling webapplikasjon fra å bruke GWT-RPC til å bruke RequestFactory. I denne sammenhgen fant vi ut at ExtGWT 2 sin BeanModelGenerator ikke er i stand til å lese getters fra proxy interface. Denne generatoren skal fikse dette problemet.

package com.wis.wisweb2.intra.core.rebind;

import java.util.List;

import com.extjs.gxt.ui.rebind.core.BeanModelGenerator;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.requestfactory.shared.BaseProxy;

/**
 * BeanModel generator with support for GWT AutoBeans.
 * 
 * @author Stig Runar Vangen
 */
public class AutoBeanBeanModelGenerator extends BeanModelGenerator {

    @Override
    protected final void addGetters(final JClassType cls,
            final List methods) {
        // Ignore methods of Object
        if (cls.getSuperclass() != null) {
            addGetters(cls.getSuperclass(), methods);
            addClassGetters(cls, methods);
        }

        if (isAutoBean(cls)) {
            addClassGetters(cls, methods);
        }
    }

    /**
     * @param cls
     *            class to test
     * @return true if given class qualify for AutoBean generation
     */
    private boolean isAutoBean(final JClassType cls) {
        if (cls.getQualifiedSourceName().equals(BaseProxy.class.getName())) {
            return true;
        }

        for (JClassType classType : cls.getImplementedInterfaces()) {
            return isAutoBean(classType);
        }

        return false;
    }

    private void addClassGetters(final JClassType cls,
            final List methods) {
        for (JMethod m : cls.getMethods()) {
            if (m.isPublic() || m.isProtected()) {
                String name = m.getName();
                if ((name.matches("get.*") || name.matches("is.*"))
                        && m.getParameters().length == 0) {
                    methods.add(m);
                }
            }
        }
    }
}

Du må også definere denne generatoren for bruk i din GWT modul definisjonsfil.

    <!-- BeanModel for AutoBean -->
    <generate-with class="com.wis.wisweb2.intra.core.rebind.AutoBeanBeanModelGenerator">
        <when-type-assignable class="com.extjs.gxt.ui.client.data.BeanModelLookup" />
    </generate-with>

Denne definisjonen burde overstyre generatoren fra ExtGWT pakken.

--Emner: Java, Web 2.0, WisWeb 2
Kommentarer: 0





ExtGWT og RequestFactory integrasjon
Av: Stig Runar Vangen Fredag 04.02.2011 (13:42)

Sencha har sagt at de for neste versjon av ExtGWT kommer til å nærme seg standardene som Google bruker for GWT. Tidligere har man i ExtGWT måtte gjøre en del spesialtilpasninger for å få dataflyt til å fungere optimalt. Vi har forsøkt å foreberede kodebasen vår i påvente av ExtGWT 3, og en sentral bit her er RequestFactory, som både reduserer mengden data som overføres mellom klient og server, samt gjør at vi ikke trenger å skrive like mye kode for å endre på data. Disse endringene spenner seg over både server og klient side av kodebasen.

Spring og RequestFactory

Bruker foreløpig servlet angitt i web.xml. Denne er uavhengig av hvilken RequestContext du bruker, men hver implementasjon av disse er ikke Spring-kompatible. Derfor står dette som et punkt på listen over ting som må utbedres.

 

ExtGWT og RequestFactory

Sencha sier selv at main i ExtGWT 3 skal bevege seg mot en bedre integrasjon mot GWT. Dette innebærer å bruke de rammeverk som allerede eksisterer i GWT. Deriblant finner vi RequestFactory (introdusert i GWT 2.1), som er et rammeverk for å minimere trafikk over nettlinjen. Dette gjøres ved å bare sende endringer gjort i modellen i stedet for hele modellen. En grunnleggende introduksjon er tilgjengelig her:

 

http://code.google.com/webtoolkit/doc/latest/DevGuideRequestFactory.html

 

Det første som slår meg når jeg leser denne dokumentasjonen, er at Google har brutt alle skikker for god programmering når de lagde dette rammeverket. Alle metoder for å hente ut data fra databasen ligger her som statiske metoder på entiteten. Det at disse metodene er statiske stopper for integrasjon mot Spring/Guice eller lignende. Det at de er plassert på entiteten gjør at koden ikke er separert i kodelag som gjør videre utvikling lettere. Dette har blitt gjort litt lettere i GWT 2.1.1, med en god del forbedringer for RequestFactory:

 

http://code.google.com/p/google-web-toolkit/wiki/RequestFactory_2_1_1

 

Man kan her dra ut implementasjon av uthenting av data fra entiteter ved hjelp av locators. Disse trenger heller ikke lenger være statiske, noe som letter implementasjon mot Spring ganske mye. Derimot er det veldig lite dokumentasjon tilgjengelig enda. Hverken Google eller bloggere har begynte skrive om det forbedrede rammeverket enda. Det har derfor vært en lang prosess med prøving og feiling for å integrere RequestFactory i vårt system.

 

RequestFactory GIN provider

  1. public class ContactRequestFactoryProvider implements
  2.   Provider<ContactRequestFactory> {
  3.  
  4.   @Inject
  5.   private CoreGinjector coreGinjector;
  6.  
  7.   @Override
  8.   public final ContactRequestFactory get() {
  9.     ContactRequestFactory contactRequestFactory =
  10.       GWT.create(ContactRequestFactory.class);
  11.     contactRequestFactory.initialize(coreGinjector.getEventBus(),
  12.       coreGinjector.getRequestTransport());
  13.     return contactRequestFactory;
  14.   }
  15. }

 

For oppretting av RequestFactory-objekter brukes en GIN-provider. Resultatet av denne er igjen bundet inn som en singleton gjennom GIN-konfigurasjonen. Denne initieres ved å bruke vår globale eventbus og en tilpasset transport-metode. Grunnen til at vi trenger en tilpasset transport-metode er at vi henter data fra en annen web-context enn den klienten ligger på.

 

RequestFactory

  1. public interface ContactRequestFactory extends RequestFactory {
  2.   ContactRequest contactRequest();
  3. }

 

Factory i seg selv henviser bare til en request implementasjon.

 

Contact request

  1. @Service(value = ContactAdapter.class, locator = InstanceServiceLocator.class)
  2. public interface ContactRequest extends RequestContext {
  3.  
  4.   Request<ContactProxy> get(String id);
  5.  
  6.   Request<Void> persist(ContactProxy contact);
  7.  
  8.   Request<Void> remove(ContactProxy contact);
  9. }

 

Her defineres de metodene man ønsker å bruke for å kommunisere fra klient til server. Dette er de metodene som er spesifikt for kontakt-modulen. Klassen er i seg selv annotert som en GWT-service, der implementasjonen av disse metodene ligger i ContactAdapter-klassen (trenger ikke lenger være entitets-klassen i GWT 2.1.1), mens ContactLocator (locators er nytt i GWT 2.1.1) tar seg av oppdateringer av entiteter.

 

Contact RequestFactory adapter

  1. @Component
  2. public class ContactAdapter {
  3.  
  4.   private static ContactDao contactDao;
  5.  
  6.   public ContactAdapter() {
  7.   }
  8.  
  9.   @Autowired
  10.   public ContactAdapter(final ContactDao contactDao) {
  11.     ContactAdapter.contactDao = contactDao;
  12.   }
  13.  
  14.   public final Contact get(final String id) {
  15.     Scanner scanner = new Scanner(id);
  16.     scanner.useLocale(Locale.ROOT);
  17.     if (scanner.hasNextLong()) {
  18.       return contactDao.get(scanner.nextLong());
  19.     }
  20.     return null;
  21.   }
  22.  
  23.   public final void persist(final Contact contact) {
  24.     contactDao.saveOrUpdate(contact);
  25.   }
  26.  
  27.   public final void remove(final Contact contact) {
  28.     contactDao.delete(contact);
  29.   }
  30. }

 

Her implementeres de metodene som er definert i request-interfacet. Klassen er tagget med @Component slik at Spring finner denne klassen gjennom auto-scanning. Vi slipper dermed spesifikk konfigurasjon per modul. En kontakt-DAO blir gitt fra Spring sin kontekst. Denne lagres som en statisk variabel. Grunnen til dette er at RequestFactory oppretter instanser av dette objektet uavhengig av Spring. Ved oppstart blir DAO overlevert fra Spring, og alle instanser av denne adapteren vil ha tilgang til gjeldende DAO.

 

Instance ServiceLocator

  1. public class InstanceServiceLocator implements ServiceLocator {
  2.  
  3.   private static final Log LOGGER = LogFactory
  4.     .getLog(InstanceServiceLocator.class);
  5.  
  6.   @Override
  7.   public final Object getInstance(final Class<?> clazz) {
  8.     try {
  9.       Object newInstance = clazz.newInstance();
  10.       return newInstance;
  11.     } catch (InstantiationException ex) {
  12.       LOGGER.fatal("Failed to create instance", ex);
  13.     } catch (IllegalAccessException ex) {
  14.       LOGGER.fatal("Failed to create instance", ex);
  15.     }
  16.     return null;
  17.   }
  18. }

 

Dette er en veldig enkel ServiceLocator som ganske enkelt oppretter nye instanser av den klassen man etterspør. Det er mulig at vi i senere tid vil trenge å hente ut data fra Spring sin context i stedet for å lage objekter utenfor.

 

Entity proxy

  1. @ProxyFor(value = Contact.class, locator = ContactLocator.class)
  2. public interface ContactProxy extends BaseEntityProxy {
  3.  
  4.   String getAddress();
  5.  
  6.   String getFirstName();
  7.  
  8.   String getLastName();
  9.  
  10.   void setAddress(String address);
  11.  
  12.   void setFirstName(String firstName);
  13.  
  14.   void setLastName(String lastName);
  15. }

 

Entitets-proxy-er blir implementert som autobeans på klientsiden. Disse er en speiling av entiteter på server-siden. Man må i proxy angi navn på metoder basert på Java Bean-standarden. Dette vil vanligvis være en speiling av de metode-navnene man finner i entiteten. Dette for at RequestFactory skal kunne hente data entiteten før de dras over til klienten. Dersom disse ikke stemmer overens får man feil ved første forsøk på uthenting av data. Merk også at vi her peker til en locator. Denne er ikke av typen ServiceLocator, som plasseres på en request.

 

  1. @Entity
  2. public class Contact extends AbstractDocumentEntity implements Serializable {
  3.  
  4.   private String firstName;
  5.   private String lastName;
  6.   private String address;
  7.  
  8.   public String getAddress() {
  9.     return address;
  10.   }
  11.  
  12.   public void setAddress(String address) {
  13.     this.address = address;
  14.   }
  15.  
  16.   public String getFirstName() {
  17.     return firstName;
  18.   }
  19.  
  20.   public void setFirstName(String firstName) {
  21.     this.firstName = firstName;
  22.   }
  23.  
  24.   public String getLastName() {
  25.     return lastName;
  26.   }
  27.  
  28.   public void setLastName(String lastName) {
  29.     this.lastName = lastName;
  30.   }
  31. }

 

Dette er et forenklet utdrag av entiteten som autobean proxy peker til. Merk at metode-kallene i proxy kaller til feltene i klassen, ikke metodene. Begge klasser følger samme regelsett for navngiving av getters/setters.

 

Contact RequestFactory locator

  1. public abstract class DocumentEntityLocator<T extends AbstractDocumentEntity>
  2.   extends Locator<T, Long> {
  3.  
  4.   private static final Log LOGGER = LogFactory.getLog(DocumentEntityLocator.class);
  5.  
  6.   public DocumentEntityLocator() {
  7.   }
  8.  
  9.   public abstract BaseDao<T> getDao();
  10.  
  11.   @Override
  12.   public final T create(final Class<? extends T> clazz) {
  13.     try {
  14.       Class<? extends T> entityClass = getEntityClass(clazz);
  15.       if (entityClass != null) {
  16.       T newInstance = entityClass.newInstance();
  17.       getDao().saveOrUpdate(newInstance);
  18.         return newInstance;
  19.       }
  20.     } catch (InstantiationException ex) {
  21.       LOGGER.fatal("Failed to create instance", ex);
  22.     } catch (IllegalAccessException ex) {
  23.       LOGGER.fatal("Failed to create instance", ex);
  24.     }
  25.     return null;
  26.   }
  27.  
  28.   @Override
  29.   public final T find(final Class<? extends T> clazz, final Long id) {
  30.     return getDao().get(id);
  31.   }
  32.  
  33.   @Override
  34.   public final Class<T> getDomainType() {
  35.     return getDao().getDomainType();
  36.   }
  37.  
  38.   @Override
  39.   public final Long getId(final T domainObject) {
  40.     return domainObject.getId();
  41.   }
  42.  
  43.   @Override
  44.   public final Class<Long> getIdType() {
  45.     return Long.TYPE;
  46.   }
  47.  
  48.   @Override
  49.   public final Object getVersion(final T domainObject) {
  50.     return domainObject.getRevisionNumber();
  51.   }
  52.  
  53.   @SuppressWarnings("unchecked")
  54.   private <X extends Object> Class<X> getEntityClass(
  55.     final Class<? extends Object> clazz) {
  56.     Entity entity = clazz.getAnnotation(Entity.class);
  57.     if (entity != null) {
  58.       return (Class<X>) clazz;
  59.     }
  60.  
  61.     Class<?> superclass = clazz.getSuperclass();
  62.     if (superclass != null) {
  63.       return getEntityClass(superclass);
  64.     }
  65.  
  66.     return null;
  67.   }
  68. }

 

En locator er bindeledded mellom din modell-struktur og RequestFactory. Her definerer du hvordan man henter ut en entitet fra en id. I tillegg definers hvordan man finner id, versjon og type fra en entitet. DAO hentes her ut gjennom en abstrakt metode.

 

  1. @Component
  2. public class ContactLocator extends DocumentEntityLocator<Contact> {
  3.  
  4.   private static final Log LOGGER = LogFactory.getLog(ContactLocator.class);
  5.   private static ContactDao contactDao;
  6.  
  7.   public ContactLocator() {
  8.   }
  9.  
  10.   @Autowired
  11.   public ContactLocator(final ContactDao contactDao) {
  12.     ContactLocator.contactDao = contactDao;
  13.   }
  14.  
  15.   @Override
  16.   public final BaseDao<Contact> getDao() {
  17.     return ContactLocator.contactDao;
  18.   }
  19. }

 

Dette er en implementasjon av en locator for en gitt modul. Denne klassen er annotert med @Component for at Spring skal behandle den ved oppstart. Den statiske kontakt DAO blir da satt. Denne må være statisk da det er RequestFactory som i ettertid vil lage nye instanser av denne, og er som kjent ikke fullstendig Spring-kompatibel. Denne gis så til den abstrakte klassen via implementeringen av DAO-uthenting. Dette gjør det raskt og enkelt å sette opp nye moduler.

 

Videre plan er å gjøre et forsøk på å utvide RequestFactory på serverside slik at vi ikke er så avhengige av statiske variabler for Spring-Beans. Dette vil gjøre at koden er bedre rustet på endringer i fremtiden.

 

 

--Emner: Java, Utvikling, Web 2.0, WisWeb 2
Kommentarer: 0





Spring og GWT-RPC integrasjon
Av: Stig Runar Vangen Torsdag 03.02.2011 (14:23)

Som en del av implementasjonen av serverbiten av WisWeb 2 har vi gjort en jobb for integrasjon GWT og Spring. I tillegg har det blitt gjort en god del på klientsiden for å integrere RequestFactory innført i GWT 2.1 mot ExtGWT. Dette har til tider vært en frustrerende opplevelse, og ønsker her å publisere noen av de løsningene vi kom frem til slik at andre slipper å oppleve den samme frustrasjonen.

 

For GWT sine RPC-kall ønsker vi å konfigurere plassering av endepunkter gjennom Spring-annotasjoner. Dette krever at vi setter opp Spring-kontrollere i stedet for GWT-servlets. Denne integrasjonen gjøres i følgende kodebit.

 

  1. public abstract class AbstractRpcController extends RemoteServiceServlet {
  2.  
  3.   private static final Log logger = LogFactory.getLog(AbstractRpcController.class);
  4.   private ServletContext servletContext;
  5.  
  6.   @Override
  7.   public final ServletContext getServletContext() {
  8.     return servletContext;
  9.   }
  10.  
  11.   @Autowired
  12.   public final void setServletContext(final ServletContext servletContext) {
  13.     this.servletContext = servletContext;
  14.   }
  15.  
  16.   public abstract RemoteService getRemoteService();
  17.  
  18.   @RequestMapping("/")
  19.   public final void request(final HttpServletRequest request,
  20.       final HttpServletResponse response) {
  21.     this.doPost(request, response);
  22.   }
  23.  
  24.   @Override
  25.   public final String processCall(final String payload)
  26.       throws SerializationException {
  27.     try {
  28.       RPCRequest rpcRequest =
  29.         RPC.decodeRequest(payload, this.getRemoteService().getClass());
  30.       String result =
  31.         RPC.invokeAndEncodeResponse(this.getRemoteService(),
  32.           rpcRequest.getMethod(), rpcRequest.getParameters());
  33.       return result;
  34.     } catch (IncompatibleRemoteServiceException ex) {
  35.       logger.error("Caught an exception", ex);
  36.       return RPC.encodeResponseForFailure(null, ex);
  37.     } catch (Exception ex) {
  38.       logger.error("Caught a generic exception", ex);
  39.       return RPC.encodeResponseForFailure(null, ex);
  40.     }
  41.   }
  42. }

 

Selve kjernen her er den siste metoden. Her rutes en GWT-service inn til GWT sin implementasjon av RPC-behandling. Dette sørger for en sømløs integrasjon mellom GWT og Spring. Referanse til GWT-service er abstract, da hver modul-implementasjon bruker sin egen service.

 

  1. @Controller
  2. @SystemController
  3. @RequestMapping("/rpc/contact")
  4. public class ContactRpcController extends AbstractRpcController {
  5.  
  6.   private ContactService contactService;
  7.  
  8.   @Autowired
  9.   public final void setContactService(final ContactService contactService) {
  10.     this.contactService = contactService;
  11.   }
  12.  
  13.   @Override
  14.   public final RemoteService getRemoteService() {
  15.     return this.contactService;
  16.   }
  17. }

 

Dette er en implementasjon av en modul-spesifikk RPC kontroller. Kontakt-service hentes her fra Spring sin kontekst, og gis tilbake til den abstrakte implementasjonen ved behov. Dette gjør det raskt og enkelt å legge til services for andre moduler.

 

--Emner: Java, Utvikling, Web 2.0, WisWeb 2
Kommentarer: 0





De tre gruppene av utviklere
Av: Stig Runar Vangen Mandag 08.03.2010 (00:00)

I forbindelse med mitt GameLib-prosjekt brukte vi klassifisering av utviklere fra Microsoft. Fant igjen denne artikkelen om forskjellige utvilkler-grupper, og bestemte meg for å oversette og legge ut denne teksten. Merk at denne sammenligningen bare sammenligner hvordan utviklergruppene tenker rundt bruken av tredjeparts biblioteker. For en mer humoristisk generell sammenligning, se også her.

 

Systematisk utviklere (Systematic programmers) har en tendens til å følge en defensiv koding stil. De gjør ikke antagelser om koden de skriver, plattformen den kjører på, klasse-bibliotekene som de bruker osv. For eksempel vil de ikke anta at et klasse-biblioteket vil oppføre seg som annonsert. I stedet vil systematiske utviklere teste biblioteket i et trygt miljø, inspisere bibliotekets kildekode etc før de bruker den i et produksjonsmiljø. Systematiske utviklere ønsker programmeringsspråk og APIer som gir dem full kontroll over eksekveringen av koden sin, og som ikke skjuler viktige detaljer fra dem, selv om det betyr at de må skrive mer kode og bruke mer tid på å forstå hvordan koden virker. De verdsetter å kunne komme under overflaten og finpusse komponenter eller erstatte dem.

 

Pragmatiske utviklere (Pragmatic programmers) har en tendens til å være mindre defensiv enn systematiske utviklere. I mange tilfeller er de mer komfortable med å gri fra seg kontrollen over koden for bedre produktivitet så lenge de er klar over fordelene de vinner. I stedet for å bruke tid på å oppnå en full forståelse av alle detaljer rundt et API, vil de foretrekker å lære underveis, å bygge opp forståelse for APIet samtidig med det arbeidet de gjør. De verdsetter å kunne komme under overflaten og finpusse komponenter når de må, men vil helst ikke måtte gjøre det.

 

Opportunistiske utviklere (Opportunistic programmers) verdsetter produktivitets-funksjoner i et språk, API eller IDE svært høyt, ofte høyere enn noe annet. I motsetning til systematiske utviklere, setter de mindre verdi i å ha full kontroll over koden deres, siden for opportunistiske utviklere kontrollen over koden mindre verdt enn utviklings-tid. De særlig verdsetter 3. parts komponenter og APIer som tillater dem å konsentrere seg om virksomhetens problemet som de prøver å løse, snarere enn på konfigurering av komponenter eller tilpasser API slik at det oppfyller deres krav. De ser ingen verdi i å kunne komme under overflate og tilpasse komponenter - de ville heller lete etter et annet API eller komponent som møter deres behov fremfor å endre komponenter eller APIer som de allerede har.


Hvilken type utvikler er du?

--Emner: Utvikling
Kommentarer: 0





Et adrenalinkick for WisWeb
Av: Stig Runar Vangen Lørdag 06.03.2010 (07:47)

For litt over en måned siden ble det gjort store endringer i hvordan WisWeb fungerer. Jeg skrev om hele motoren for WisWeb fra grunnen av med tanke på å oppnå bedre ytelse og stabilitet. Samtidig la drifts-avdelingen over til en annen webserver. Hva var det så vi oppnådde med disse endringene?

 

Ytelse

Metodikken for hvordan data blir hentet ut fra databasen ble gjort helt om. Dette resulterte i at vi gjennomsnittlig reduserer vekt på databasen med to tredjedeler. I tillegg er teknikken for å bygge opp sider endret så mye at det nesten ikke trykker serveren overhodet. På toppen av det har vi nå intern cache på sidene som gjør at de fleste forespørseler ikke engang blir prosessert av serveren. Summen av alt dette er at serverene våre nå bruker langt mer tid på å sove.

 

Responsivitet

Alle ytelses-forbedringene resulterte i en bedre brukeropplevelse for brukerene. Se for eksempel oppstartstiden for intranettet, som nå er redusert betydelig. Både internett-sider og intranettet oppdaterer innholdet langt raskere som en følge av dette.

 

Forutsigbarhet

Dette er mest for oss som jobber med systemet. Vi kan si at en endring vi gjør alltid gir oss det vi regner med å få ut. Dette stemte vanligvis også før, men nå er det ingen kjente merkeligheter igjen.

 

Stabilitet

Systemet gir oss nå bedre tilbakemelding dersom noe ikke går etter planen. Noen kunder har i det siste opplevd at vi har ringt dem opp for å si at det de ikke fikk til å gjøre tidligere nå fungerer. Det uten at kunden har kontaktet oss om problemer som har oppstått. I tillegg fant jeg en innstilling i vår app-server som lot brukere være innlogget selv etter at våre servere har vært nede. En del brukere har nok merket innimellom at de har blitt logget ut i løpet av natten dersom de gikk fra maskinen logget på WisWeb. Brukere vil nå ikke merke dette med mindre de gjør noe arbeide i det øyeblikket vi tar ned systemet.

 

Konklusjon

De forbedringene vi har gjort i det siste har gjort at systemet nå er i bedre stand enn det noensinne tidligere har vært. Jeg har fremdeles flere ideer rundt hvordan vi kan få systemer til å yte mer, men det får vente til en senere gang. Det vi har nå gir oss langt bedre albuerom nå når vi starter med utviklingen av WisWeb 2.

--Emner: Database/SQL, Debugging, Java, JVM, Servere, WisWeb 1
Kommentarer: 0





Eksport av bilder fra Java
Av: Stig Runar Vangen Torsdag 16.08.2007 (09:00)

I den siste tiden har jeg jobbet litt med bildebehandling i forbindelse med WisWeb 2. Jeg kan med en gang si at den bildebehandlingen vi hadde i WisWeb 1 kommer til å bli kraftig forbedret. Ikke nok med at det har blitt lagt til en del nye effekter, men det har også blitt korrigert en del på de gamle. Enkelte av de bildeoperasjonene vi støttet den gangen fungerte fint, men ga ikke den absolutt beste mulige bildekvaliteten. Det gjør den nå.

 

Det største problemet så langt har egentlig vært å eksportere bildene fra Java etter at endt bildebehandling er gjennomført. Vi ønsker denne gangen å støtte korrekt eksport av transparente bilder. I den forrige utgaven hendte det i noen tilfeller at bilder som var satt til å være transparente ikke ble det lenger etter en del behandling. All behandling støtter nå transparente bilder. Det siste problemet var selve eksporten av bildene fra ferdigbehandlet bilde i Java til et bilde vi kan presentere i nettleseren. Til å begynne med ønsker vi å støtte JPEG, GIF og PNG. Her finnes det mange løsninger, og det er ikke alltid det enkeleste som er det beste. Java 6 har i utgangspunktet støtte før eksport til alle disse formatene, men med noen bakdeler for enkelte av dem.

 

JPEG

  • Java 6 - Ypperlig eksport av bilder. Kvalitet kan fintunes til man blir blå i trynet. Eksportering av JPEG-filer i Java har eksistert som et gjemt bibliotek i standard-pakken siden.. tja.. ikke så alt for langt unne tidenes morgen iallefall, og er utrolig kjapp.

Vi gikk selvsagt for Java sin innebygde støtte uten noen mer vurdering her.

 

PNG

  • Java 6 - Bildene blir eksportert fullstendig perfekt, med transparens osv, men.. fy fader hvor tregt.
  • Catcode - Bilder ble ikke transparente.
  • Objectplanet - Ypperlig hastighet, langt bedre enn den originale. Men.. enkelte bilder ble korrupte.

Valget ble selvsagt Java sin innebygde eksport, til tross for at den ikke var så alt for rask. Dersom noen vet om et ber alternativ, vennligst ta kontakt.

 

GIF

Enda noen problemer her: Gjøre om true-color til 256 farger (color quantizing), transparens, blending.

  • Java 6 - Bildene ble gjort om fra true-color til indeksert palett (noe dårlig farge-redusering), men manglet transparens.
  • ACME - Støtter ikke redusering av farger.
  • Gurge - Støtter ikke redusering av farger.
  • Gif4J - Utrolig god farge-redusering. Transparens ble perfekt. Mangler bare blending.

Jeg har vært i kontakt med utviklerene av Gif4j i forbindelse med blending, og fikk positiv tilbakemelding på dette. Selv uten blending er deres programvare best på markedet.

 

 

 

 

--Emner: Java, WisWeb 2
Kommentarer: 0





Prosess
Av: Stig Runar Vangen Torsdag 09.08.2007 (09:06)

Har jobbet en del med editor for prosess-skjema i det siste. Som grunnlag for denne editoren har vi brukt et eksternt bibliotek som heter Open-jACOB Draw2D. I utgangspunktet støttet ikke editoren alle de funksjonene vi ønsket oss, så en god del objekter ble lagt til av oss. Sluttresultatet ble ikke så alt for ille, som du kan se i følgende skjermdump:

 

Prosess

 

Det som virkelig imponerer meg med dette biblioteket, er oppdateringsfrekvensen. Dersom du kikker nedover hjemmesiden til prosjektet, ser du at biblioteket har blitt oppdatert nesten daglig. Flere av de funksjonene vi implementerte da vi begynte på dette prosjektet har allerede blitt implementert av den originale utvikleren. Noen av de nye funksjonene er også noe vi ønsker oss, men jeg tror det er best om vi venter litt med å legge til disse i vår editor. Med den hastigheten de utvikler nye elementer i bilioteket sitt, vil vi bare bli sittende og oppdatere denne editoren hvis vi skulle følge deres oppdateringer.

--Emner: Ajax, JavaScript, Web 2.0, XML
Kommentarer: 0


 
 Nye poster
Fixing missing (30.05.2012)
Redirect dll us (30.05.2012)
Laste ned passo (11.05.2012)
Bare si "Nei ti (12.12.2011)
Posten er slett (16.11.2011)
 Søk
 
 Populære emner
Access  Ajax  Ansatte  Brannmur  Database/SQL  Debugging  Delphi  FortiClient  Fortigate  GSI  Hjemmet  Html  Internett  iPhone  iPhone Apps  Java  JavaScript  JVM  Nerdehumor  Nettverk  Operativsystem  Palm  Servere  Skrivere  Sybase  Utvikling  VBA  Vista  VPN  Web 2.0  Windows  WinXP  WIS  Wis Tiltak  WisWeb 1  WisWeb 2  Word  XML
 Vis måned
Mai 2012 (3)
Desember 2011 (1)
November 2011 (1)
September 2011 (2)
August 2011 (1)
 Vis fra forfatter
Ove Halseth (46)
Dag Waade (9)
Stig Runar Vangen (7)
Svein Waade (6)
Inge Valaas (1)
Inger Berg (1)
Kristian Ljøkelsøy Vitsø (1)