gwt-maven-plugin: fordítás részletesen + futtatás dev mode-ban

Használjuk a következő pom.xml-t, figyelve főként a build->outputDirectory property-re, valamint a két gwt-maven-plugin-os konfigurációra:



<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>hu.jbuzi.sandbox</groupId>
<artifactId>gwt-maven-module-A</artifactId>
<packaging>war</packaging>
<version>1.0.0-SNAPSHOT</version>
<properties>
<gwt.version>2.0.4</gwt.version>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-servlet</artifactId>
<version>${gwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<version>${gwt.version}</version>
<scope>provided</scope>
</dependency>

<!-- test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>hu.jbuzi.sandbox</groupId>
<artifactId>gwt-maven-module-B</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<!--
mikor eclipse .project es .classpath fajlokat keszitunk a 'mvn eclipse:eclipse' paranccsal, akkor az outputDirectory erteke hatarozza meg, hogy mi lesz a default target path az eclipse-ben forditaskor, tehat ezzel tudjuk elerni, hogy eclipse-ben futtatva a gwt alkalmazast, a modositasaink szerver- es browserrefresh nelkul eletbe lepjenek
-->
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.3-SNAPSHOT</version>
<configuration>
<!--
a gwt-maven-plugin runTarget property erteke hatarozza meg, hogy 'mvn gwt:run'-nal inditott, dev/hosted mode altal feldobott segedablak 'Launch default browser' gombja milyen url-re dobjon
-->
<runTarget>Gwt_module_A.html</runTarget>

<!--
a gwt-maven-plugin hostedWebapp property erteke hatarozza, hogy a 'mvn gwt:run'-nal inditott jetty melyik konyvtarat hasznalja, mint war konyvtar, tehat hol keresse a webapp-ot (default ertek a /war lenne)
-->
<hostedWebapp>
${project.build.directory}/${project.build.finalName}
</hostedWebapp>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.0.2</version>
</plugin>
</plugins>
</build>
</project>


Ekkor:


1, 'mvn compile' elkészíti a target/gwt-maven-module-A-1.0.0-SNAPSHOT/WEB-INF/classes könyvtárat, plusz a tartalmát, azaz a src/main/java alól lefordított .java fájlok .class kimenetét, plusz az src/main/resources alól odamásolja a fájlokat. Kommentbe is odaírtam, de mégegyszer: nem a maven miatt kell, hogy ide generálódjon, hanem azért, mert ha majd eclipse-es projektet készítünk ebből mvn eclipse:eclipse-szel, akkor ne kelljen kézzel beállítanunk a Default output folder-t.


2, 'mvn war:war' vagy 'mvn package' a target/gwt-maven-module-A-1.0.0-SNAPSHOT/ alá beteszi a nyitó html-t és css-t (nálam Gwt_module_A.html és Gwt_module_A.css a legalapabb Greetings alkalmazásból), plusz a target/gwt-maven-module-A-1.0.0-SNAPSHOT/WEB-INF/lib -et létrehozza és bemásolja a jar-okat, valamint a target/gwt-maven-module-A-1.0.0-SNAPSHOT/WEB-INF/web.xml -t is odamásolja.


3, 'mvn gwt:compile' elvégzi a lassú gwt-s kompájlt, majd a megszületett modulkönytárat javascriptesTÜL és hátéemelesTÜL odateszi a target/gwt-maven-module-A-1.0.0-SNAPSHOT/ alá (nálam ez a modulkönyvtár: gwt_module_a).


4, 'mvn gwt:run' dev mode-ban elindítja az alkalmazást a target/gwt-maven-module-A-1.0.0-SNAPSHOT alól.



Tegyük hozzá gyorsan, hogy nekem az sosem szempont, hogy maven-esen commandline indítható legyen dev mode-ban a gwt-s project, ez inkább csak valami plusz; dev mode-ban mindig Eclipse-ben futtattom az appot.
A lényeg , hogy maven-esen forduljon az alkalmazás (gwt-s javascript generálással együtt) a Hudson miatt, hogy eclipse-ben mindenféle debug varázslás (hot code replacement kliensoldalon és szerveroldalon) működjön dev mode-ban, valamint, hogy a Hudson által készített war rilíz tomcat alá deployolva automatikusan fusson. Ezzel a pom.xml -lel és a belőle 'mvn eclipse:eclipse'-szel készített eclipse projekttel ezek működnek.

gwt-maven-plugin: gwt-s újrafordításhoz szükséges dolgok a jar-ba

Tegyük fel, hogy gwt-s kliensoldali modulunkat abszolút újrafelhasználhatóvá akarjuk tenni, tehát egy különálló jar-t generálnánk belőle, amire később egy másik gwt-s kliensoldali projekt/modul dependálhat. GWT ahhoz, hogy optimális javascriptet generáljon, mindig teljes kliensoldali forráskódból fordít, tehát magyarul a jar-ba bele kell kerüljenek a .java fájlok is a .class-ok mellé, plusz legalább még a modulleíró gwt.xml fájl. Kétféleképp tudjuk ezt elérni a pom.xml-ben:



1, A fapadosabb megoldás, ha az alap maven resource-másolgatós fícsörjével tesszük ezt:




...



src/main/java

**/*.java



src/main/resources

**/*.gwt.xml




...



2, Közel ekvivalens megoldás, viszont tisztább, szárazabb, jobb, ha a gwt-maven-plugin -nal tesszük ezt:



...



org.codehaus.mojo
gwt-maven-plugin
1.2



resources






...



A 2,-es megoldásnak előnye többek közt, hogy nem kell beégetni, hogy src/main/java vagy src/main/resources alatt van a gwt.xml (ez azért fontos, mert a Google Eclipse Plugin-nek voltak/vannak problémái azzal, ha nem az src/main/java alatt van ez a leíró). Másik előny, hogy ha esetleg csak szerveroldali kódok is vannak a jar-ban, akkor azok mellé nem másol fölöslegesen .java forrásfájlt is, ezzel kisebb az eredmény jar mérete.

GWT (2.0) + maven + több projektes fejlesztés

Múltkor megnéztük, hogyan lehet m2eclipse segítségével gwt-zni maven-es környezettel. Egy probléma azonban volt az eredménnyel, mégpedig az, hogy abban az esetben, ha több projektre akartuk szétbontani az alkamazásunkat, együtt kellett élnünk két maven parancs futtatással, amelyeket minden egyes függőség projekt módosítás után futtatni kellett: mvn install (a függőség projekten) + mvn package (a gwt projekten). Ez sajnos fájdalmas nagy projekt esetén.


Közben viszont Józsa Kristóf rámutatott a maven eclipse plugin (hogy egyértelműbb legyen: az, amit mvn eclipse:eclipse -szel kell futtatni) egy számomra eddig ismeretlen fícsörére, nevezetesen, hogy nem csak egyszerűen a lokális maven repót címezi meg a függőség jar-ok lelőhelyeként, hanem a workspace-ünkben levő projektekre közvetlenül dependál. Szerintem ez a több projektes fejlesztés létminimuma, szóval meg kellett tudnom, hogyan is kell ezt. Lelövöm a poént, annyi a lényeg, hogy kell csinálni egy parent projektet, amiben a <modules> alatt fel van sorolva az összes projekt, ami a workspace-ünkbe is bekerül, majd ezen a parent-en futtatni az mvn eclipse:eclipse -et. (Hozzáteszem, hogy én a flat maven projekthierarchiát részesítem előnyben, tehát ahol a szülő a gyerekekkel egy szinten van).


Most akkor nulláról dobjunk össze egy többprojektes próbát (m2eclipse így most nem játékos, command line futtatjuk a maven-t, ezenkívül eclipse kell és google plugin). Verziók az előző bejegyzésem szerintiek.



  1. Csináljunk egy google webapp-ot, ezt alakítjuk át majd maven-esre. Így legalább kapunk egyből egy tesztkörnyezetet, azaz a Greetings app-ot.



  2. Alakítsuk át a projektstruktúrát maven-esre: csináljunk src/main/java forráskönyvtárt eclipse-ben az src helyett. Így néz ki az eredmény:



  3. Csináljuk meg azt a maven projektet, ami a függősége lesz a gwt projektnek: groupid: hu.jbuzi.sandbox; artifactid: gwt-maven-eclipse-dependency; version: 1.0.0-SNAPSHOT. pom.xml:


    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    4.0.0
    hu.jbuzi.sandbox
    gwt-maven-eclipse-dependency
    jar
    1.0.0-SNAPSHOT

    1.6
    1.6




    junit
    junit
    4.7
    test





    org.apache.maven.plugins
    maven-compiler-plugin
    2.1

    ${maven.compiler.source}
    ${maven.compiler.target}








  4. Csináljuk meg a parent projektet (csak pom-ot tartalmaz). Itt a pom.xml hozzá:

    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    4.0.0
    hu.jbuzi.sandbox
    gwt-maven-eclipse-parent
    1.0.0-SNAPSHOT
    pom
    gwt-maven-eclipse-parent

    1.6
    1.6


    ../gwt-maven-eclipse-dependency
    ../gwt-maven-eclipse




    org.apache.maven.plugins
    maven-compiler-plugin
    2.1

    ${maven.compiler.source}
    ${maven.compiler.target}



    org.apache.maven.plugins
    maven-eclipse-plugin
    2.8







  5. Másoljuk be ezt a pom.xml-t a gwt-s projekt könyvtárába (gwt-maven-eclipse):


    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    4.0.0
    hu.jbuzi.sandbox
    gwt-maven-eclipse
    war
    1.0.0-SNAPSHOT

    2.0.2
    1.6
    1.6



    com.google.gwt
    gwt-servlet
    ${gwt.version}
    runtime


    com.google.gwt
    gwt-user
    ${gwt.version}
    provided




    junit
    junit
    4.7
    test





    org.codehaus.mojo
    gwt-maven-plugin
    1.2


    org.apache.maven.plugins
    maven-war-plugin
    2.0.2







  6. gwt-maven-eclipse-parent könyvtárban állva, futtassunk egy mvn eclipse:eclipse -et.

  7. gwt projekten még kell kicsit reszelni (ezt sejteti, ha Refresh-t/F5-öt nyomunk eclipseben rajta, hibák jönnek), hogy teljesen maven-es legyen. Csináljuk src/main/webapp könyvtárat (nem kell, hogy source könyvtár legyen), mozgassuk bele a .css és .html fájlokat, csináljunk WEB-INF-et, abba meg mozgassuk bele a web.xml-t (végén mutatok screenshotot).

  8. Továbbra is a gwt projekten: jobb gomb -> Properties -> Google -> Web Application: This project has a WAR directory-nál legyen bent a pipa és src/main/webapp -ra írjuk át, és a Launch and deploy from this directory-ról vegyük le a pipát:




  9. gwt-s projektben commandline futtassunk egy mvn package-t, hogy létrehozza a megfelelő war könyvtárat, és így ebbe bele tudjuk irányítani a lefordított .class-okat. Jobb klatty -> Properties -> Build path -> Default output folder: gwt-maven-eclipse/target/gwt-maven-eclipse-1.0.0-SNAPSHOT/WEB-INF/classes:




  10. Csekkoljuk, hogy minden klappol-e. Fordítsuk le a google eclipse pluginnal a projektet. Jobb gomb -> Google -> GWT compile. A WAR folder kiválasztásnál a target/gwt-maven-eclipse-1.0.0-SNAPSHOT -ot adjuk meg, úgylesz jó.


  11. Futtassuk is, jobb klatty -> Run as... -> Web application. WAR könyvtár megadásnál ugyanazt adjuk meg, mint fordításnál: target/gwt-maven-eclipse-1.0.0-SNAPSHOT.


  12. Namost importáljuk be a függőség projektet eclipse-be (ami igazából még nincs bekötve függőségként). Jobb gomb -> Import... -> Existing projects into Workspace.


  13. src/main/java -ba hu.jbuzi.sandbox.gwtmaveneclipsedependency alá vegyük fel a GreetingsMsgCreator osztályt:

    package hu.jbuzi.sandbox.gwtmaveneclipsedependency;

    public class GreetingsMsgCreator {
    public String createMsg(){
    return "csipcsupcsodák";
    }
    }



  14. Tegyük be a gwt (gwt-maven-eclipse) projekt pom.xml -jébe függőségnek a gwt-maven-eclipse-dependency-t:


    hu.jbuzi.sandbox
    gwt-maven-eclipse-dependency
    1.0.0-SNAPSHOT




  15. Commandline a parent projektben futtassuk az mvn eclipse:eclipse -et megint, hogy végre láthassuk a csodát. Eclipse-ben ilyenkor utána mindig refresheljünk.


  16. Namost egy ilyen mvn eclipse:eclipse elront két dolgot az eddigi beállításainkon: az egyik, hogy visszaállítja a default output folder-t a target/classes-ra. Ezt könnyen orvosolhatjuk, írjuk a pom.xml <build> node alá: <outputDirectory>target/gwt-maven-eclipse-1.0.0-SNAPSHOT/WEB-INF/classes</outputDirectory>. A másik, hogy a GWT SDK library függőséget megszűnteti, erre nem tudok szép megoldást, minden mvn eclipse:eclipse után nyomjunk jobb gombot a projekten -> Google -> Web Toolkit -> és vegyük ki a pipát, majd egyből tegyük vissza, ezzel visszatér a világ rendje. Azt hiszem, ez kibírható áldozat.


  17. GreetingServiceImpl greetServer fv.-ének az utsó sorát írjuk át, hogy a mi jó kis üzenetkreálónkat is használja:

    return "Hello, " + input + "!

    I am running " + serverInfo
    + ".

    It looks like you are using:
    " + userAgent + "
    "+ new GreetingsMsgCreator().createMsg();



  18. futtassuk az alkalmazást debug módban(jobb klatty -> Debug as... -> Web Application).
    Tesztelhetjük, ha átírjuk a csipcsupcsodák szöveget. Nem csak, hogy a két maven parancsot megúsztuk, de az egész szerver restartot is.




Azaz szerver újraindítás nélkül tudunk szerveroldali módosításokat végezni, ezek egyből életbe lépnek (persze szokásos restrikciókkal: metódus szignatúrát nem érinthet a változás) + nem kell szenvednünk az m2eclipse-es bugoktól (kilőhetetlen végtelen build proecessek, stb.).


Végül egy kép a két projekt layoutjáról + a végső pom.xml a gwt-maven-eclipse projektben:







xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
hu.jbuzi.sandbox
gwt-maven-eclipse
war
1.0.0-SNAPSHOT

2.0.2
1.6
1.6



com.google.gwt
gwt-servlet
${gwt.version}
runtime


com.google.gwt
gwt-user
${gwt.version}
provided


hu.jbuzi.sandbox
gwt-maven-eclipse-dependency
1.0.0-SNAPSHOT



junit
junit
4.7
test



target/gwt-maven-eclipse-1.0.0-SNAPSHOT/WEB-INF/classes


org.codehaus.mojo
gwt-maven-plugin
1.2


org.apache.maven.plugins
maven-war-plugin
2.0.2




GWT (2.0) projekt felállítása maven2-vel és m2eclipse-szel

Célok:
  1. pom.xml -ben kelljen csak leírni a projekt függőségeit (ne eclipse függően a .classpath fájlban)
  2. forduljon le a projekt eclipse-ben (m2eclipse-ben igazából)
  3. forduljon le a projekt parancssori maven-nel
  4. indítható legyen a projekt eclipse-ből (m2eclipse-ben igazából)
  5. debugolható legyen a projekt eclipse-ben, de ne remote debugging módon (tehát ne egy debug porton csatlakozva az alkalmazáshoz), hanem rendesen
  6. ne keveredjenek a generált dolgok (itt most a maven által fordítás közben generált dolgokra gondolok) a kézzel létrehozottakkal, hogy könnyen lehessen a verziókövetést (pl. svn) kezelni
  7. kliensoldali módosításokhoz ne kelljen újraindítani a szervert
  8. multiprojekt kezelése m2eclipse-ben működjön: azaz, ha a Workspace Resolution be van kapcsolva, akkor ne jar-ból szedje a projektet, hanem workspace-ből
Ami kell:
  1. J2EE-s eclipse (én a Galileo-t használom)
  2. m2eclipse plugin: nagyjából mindegy, hogy melyik verzió, én jelenleg a 0.10.0.20100209-0800 -t használom
  3. Google Plugin for Eclipse (továbbiakban GEP) : 1.3.1 fölötti kell, én az 1.3.2-eset használom



Projekt felállítása:
  1. jobb gomb package v. project explorerben -> New... -> Dynamic Web Project (!! tehát nem maven-es archetypeból építkezünk m2eclipse-es projektlayouttal)



  2. a Java oldalon be kell allitani a hagyományos maven-es forráskönyvtárakat (src/main/java, src/main/resources, ...) és a default output foldert target/classes-ra kell állítani átmenetileg


  3. Web Module oldalon a Content directory src/main/webapp legyen


  4. Finish után ezt kell látni:


  5. Project properties-ben (jobb gomb a projekten -> Properties) Google -> Web Toolkit -> Use Google Web Toolkit pipa be (ezzel gyakorlatilag beizzítottuk a Google Eclipse Plugint)


  6. Ugyanitt Google -> Web Application -> "This project has a WAR directory"-nál a pipa be + WAR directory: src/main/webapp + "Launch and deploy from this directory" pipa KI (!!)


    Ez a pont az, ami miatt a Google Eclipse Plugin 1.3.1 fölötti verziója kell (amit mellesleg nemrég, 2010. márc. végén adtak ki), ugyanis korábban ez a képernyő nem létezett a pluginban, így a WAR alapját képző forráskönyvtár nem lehetett maven-es layoutban. A "Launch and deploy from this directory"-t azért kell kivenni, mert mi maven-nel a target alá fogjuk elkészíteni a war folder-t (a lefordított class-okkal, meg a belemásolt lib-ekkel), és onnan akarjuk majd indítani a projektet. Lásd később.
  7. Kezdjünk neki a maven-esítésnek. Dobjunk be egy pom.xml-t a projekt könyvtárba. Pl.:



    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    4.0.0
    hu.jbuzi
    gwt-m2eclipse
    war
    1.0.0

    2.0.2
    1.6
    1.6



    com.google.gwt
    gwt-servlet
    ${gwt.version}
    runtime


    com.google.gwt
    gwt-user
    ${gwt.version}
    provided




    junit
    junit
    4.7
    test




  8. Jobb gomb a projekten -> Maven -> Enable Dependency Management
  9. Jobb gomb a projekten -> Maven -> Update project configuration
  10. Csak azért, hogy tesztelhessük az eredményt, csináljuk gyorsan egy sima új (Google) Web Application Project-et, amibe a GEP beleteszi a példa Greetings applikáció fájljait
  11. Másoljuk be a fájlokat (*.java, web.xml, *.css és *.html fájlokat is) a mi projektünkbe. Köv. pont után mutatok egy project layout-ot.
  12. Ha vannak TOMCAT lib-ek a classpathunkon (ezek nem feltétlen kellenek), akkor cseréljük meg a GWT SDK és a TOMCAT libek sorrendjét, tehát a GWT SDK legyen feljebb.


  13. Futtassunk egy "mvn clean package" -t a projektre, amihez felvehetjük az m2eclipse-ben a következő Run configurationt:


  14. Elkészült a gwt-m2eclipse/target/gwt-m2eclipse-1.0.0 könyvtár, amibe belepillantva látható, hogy minden bennevan, ami egy webes projekthez kell, viszont semmi gwt-s dolgot nem tartalmaz. Hogyan is tartalmazhatna, hiszen mavent futtattunk rajta, gwt plugin/fordító parancsok nélkül. Tehát futtassuk le a GEP-os fordítást: jobb klikk a projekten -> Google -> Compile és a "WAR Directory Selection" képernyőn válasszuk ki a project-name/target/project-name-x.x.x könyvtárat, tehát nálam ez a gwt-m2eclipse/target/gwt-m2eclipse-1.0.0.
  15. Indíthatjuk a projektet: jobb klikk -> Run as... -> Web Application. Első alkalommal ki kell választanunk a WAR folder-t, tehát megint ugyanazt, mint fordításnál: project-name/target/project-name-x.x.x könyvtárat, tehát nálam ez a gwt-m2eclipse/target/gwt-m2eclipse-1.0.0

    Hol tartunk?A célok közül az 1, 2, 4, 5, és a 6, eddig teljesülni látszik (ha debuggal indítod, akkor debugolható).


  16. Nézzük, hogyan lehet csak maven-nel, GEP nélkül fordítani GWT-s projektet. Kell hozzá a gwt-maven plugin 1.2-es verziója, tegyük be a pom.xml-be a alá az alábbiakat (végén bekopizom az egész pom.xml-t is):




    org.codehaus.mojo
    gwt-maven-plugin
    1.2


    org.apache.maven.plugins
    maven-war-plugin
    2.0.2



  17. mvn clean gwt:compile package -t futtassunk rajta. Így lefordul maven-esen is (3-as cél pipa), hasznos, ha például hudsonnal automatikusan akarjuk buildeltetni.


  18. Ahhoz, hogy a kliensoldali változások azonnal életbe lépjenek, át kell állítanunk az output foldert a fordításnál (jobb klatty -> Properties -> Java Build Path menüpont alatt). Lényeg, hogy az src/main/java és src/main/resources könyvtárakból az eredmény a project-name/target/project-name-x.x.x/WEB-INF/classes generálódjon:




Tehát a célok közül az utolsón kívül az összes teljesül. Az utolsóhoz még nem találtam meg a megoldást, minden esetben jar-ba kell csomagolni a függőségeket (mvn install-t kell futtatni rájuk), hogy a classpathra kerülhessen a változás.

Végül egyben az egész pom.xml:



xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
hu.jbuzi
gwt-m2eclipse
war
1.0.0

2.0.2
1.6
1.6



com.google.gwt
gwt-servlet
${gwt.version}
runtime


com.google.gwt
gwt-user
${gwt.version}
provided




junit
junit
4.7
test





org.codehaus.mojo
gwt-maven-plugin
1.2


org.apache.maven.plugins
maven-war-plugin
2.0.2





Asterisk, MeetMe, Zaptel, ZtDummy, Dahdi

A BigBlueButton-ös Fred Dixon nagyon jól összefoglalta, hogy mik a címben említett dolgok.

"We use Asterisk for the voice conferencing component, which enables us to allows us to mix incoming VoIP calls originate from within BigBlueButton and calls that come through the regular plain old wtelephone system. When running, Asterisk historically expects to have a special PCI card installed that would accept incoming signals from phone network (usually through a cable that looks like an Ethernet cable, but is actually a primary rate interface, which provides a maximum of 23 incoming lines and 1 data line). This PCI card also supplies a hardware timer that gives a consistent signal, say once every 100 milliseconds. Within Asterisk the default voice conferencing module is MeetMe. For whatever reason, MeetMe needs a timer to work. No timer, no voice conferencing. Over the years, there are Asterisk modules that provide a software timer (zaptel dummy or Dahdi), but both of these are Kernel modules, which require compilation against the kernel headers for the current linux setup.
The problem .... Unfortunately, package management systems (such as apt-get or rpm) don't support dynamic compiling of kernel modules. We can compile the module in the BigBlueButton VM (as you can see from the initial boot sequence), but not from within packages. This means, our goal of ultimately enabling anyone to install BigBlueButton with just a few commands, the primary command being
sudo apt-get install bigbluebutton
can't be reached using MeetMe. Currently, our install instructions using packages say "This installs everything except Asterisk, and for information how to do that, see these instructions." A recent thread on our forum that was over fifty messages long attests to the difficulty of setting up a kernel module. Also, many virtual host environments will not let the users install kernel modules (for obvious reasons), so it further restricts where developers can run BigBlueButton. We will still support MeetMe, but once we have support for App_Konference, we'll be able to update the packages and have BigBlueButton install on Ubuntu 9.04 with just a few commands. This means our developers need only spend a few minutes installing BigBlueButton and can focus more effort on integrating and extending BigBlueButton for the benefit of everyone."

Még annyit hozzá, hogy a Dahdi az az új neve a Zaptel-nek, valami jogi / copyright problémák állnak a háttérben.

OpenOffice dokumentumból szöveg kinyerése

Ismét .NET

Most éppen megnyitott OpenOffice dokumentumból kell kiszedni a szöveget. A letöltött OpenOffice SDK-ból kell betenni a References-be az öt darab cli_*.dll -t. Aztán:


public class OpenOfficeReceiver : ITextReceiverInterface.ITextReceiver
{

private XTextDocument oDoc;

public void createDocument()
{
XComponentContext oStrap = uno.util.Bootstrap.bootstrap();
XMultiServiceFactory oServMan = (XMultiServiceFactory)oStrap.getServiceManager();
XComponentLoader oDesk = (XComponentLoader)oServMan.createInstance("com.sun.star.frame.Desktop");
string url = @"private:factory/swriter";
PropertyValue[] propVals = new PropertyValue[0];
oDoc = (XTextDocument)oDesk.loadComponentFromURL(url, "_blank", 0, propVals);
}

public String giveBackTheTextContent()
{
return oDoc.getText().getString();
}
}
Már megint egy bejegyzés, ami .NET-es és nem Java-s. Az alábbi kód a "Word" title-lel rendelkező alkalmazáson figyeli az Enter gomb lenyomását.


public class FilterLogic{

public delegate void filteredEvent();

private filteredEvent currentFilteredEvent;
private InfoDelegate infoDelegate;
private Logger logger;

public FilterLogic(InfoDelegate infoDelegate)
{
this.infoDelegate = infoDelegate;
this.logger = new Logger(infoDelegate, "FilterLogic");
}

public void setFilteredEvent(filteredEvent currentFilteredEvent){
this.currentFilteredEvent = currentFilteredEvent;

}



public void filterEnterAndApp(IntPtr a, ref Hook.KBDLLHOOKSTRUCT lParam)
{

//ENTER KEY
if (0X0D == lParam.vkCode)
{

try
{

IntPtr hwnd = APIFuncs.getforegroundWindow();
Int32 pid = APIFuncs.GetWindowProcessID(hwnd);
Process p = Process.GetProcessById(pid);
String appName = p.ProcessName;
String appltitle = APIFuncs.ActiveApplTitle().Trim().Replace("\0", "");
Console.WriteLine(appltitle);
if (appltitle != null && appltitle.Contains("Word"))
{
if (currentFilteredEvent != null)
{

currentFilteredEvent();

}
else
{
logger.logMsg(Logger.WARNINGTYPE, "there is no filteredEvent is set, so no function will be called.");

}
}

}
catch (Exception ex)
{
logger.logException(ex);
}
}
}
}


public static class Hook
{
//Similar class is on this site:
//http://blogs.msdn.com/toub/archive/2006/05/03/589423.aspx

private static class API
{

//dll imports for hooking and unhooking and sending events trough hook hierarchy

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(
int idHook,
HookDel lpfn,
IntPtr hMod,
uint dwThreadId);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(
IntPtr hhk);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CallNextHookEx(
IntPtr hhk,
int nCode,
IntPtr
wParam,
//IntPtr lParam);
ref KBDLLHOOKSTRUCT lParam);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(
string lpModuleName);

}

public struct KBDLLHOOKSTRUCT
{
public int vkCode;
int scanCode;
public int flags;
int time;
int dwExtraInfo;
}

public delegate IntPtr HookDel(
int nCode,
IntPtr wParam,
ref KBDLLHOOKSTRUCT lParam);

public delegate void KeyHandler(
IntPtr wParam,
ref KBDLLHOOKSTRUCT lParam);

private static IntPtr hhk = IntPtr.Zero;
private static HookDel hd;
private static KeyHandler kh;

//Creation of the hook
public static void CreateHook(KeyHandler _kh)
{
Console.WriteLine("CreateHook _kh: " + _kh);
Process _this = Process.GetCurrentProcess();
ProcessModule mod = _this.MainModule;
hd = HookFunc;
kh = _kh;

hhk = API.SetWindowsHookEx(13, hd, API.GetModuleHandle(mod.ModuleName), 0);
//13 is the parameter specifying that we're gonna do a low-level keyboard hook
//Console.WriteLine(Marshal.GetLastWin32Error().ToString());
//MessageBox.Show(Marshal.GetLastWin32Error().ToString()); //for debugging
//Note that this could be a Console.WriteLine(), as well. I just happened
//to be debugging this in a Windows Application
}

public static bool DestroyHook()
{
//to be called when we're done with the hook

return API.UnhookWindowsHookEx(hhk);
}

//called when key is active
private static IntPtr HookFunc(
int nCode,
IntPtr wParam,
ref KBDLLHOOKSTRUCT lParam)
{
//Console.WriteLine("nCode=" + nCode);
//Console.WriteLine("wParam=" + wParam);

int iwParam = wParam.ToInt32();
//depending on what you want to detect you can either detect keypressed or keyrealased also with a bit tweaking keyclicked.
if (nCode >= 0 && (iwParam == 0x100 ||
iwParam == 0x104)) //0x100 = WM_KEYDOWN, 0x104 = WM_SYSKEYDOWN
kh(wParam, ref lParam);

return API.CallNextHookEx(hhk, nCode, wParam, ref lParam);
}
}



class APIFuncs
{

#region Windows API Functions Declarations

//This Function is used to get Active Window Title...
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern int GetWindowText(IntPtr hwnd, string lpString, int cch);

//This Function is used to get Handle for Active Window...
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern IntPtr GetForegroundWindow();

//This Function is used to get Active process ID...
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern Int32 GetWindowThreadProcessId(IntPtr hWnd, out Int32 lpdwProcessId);

#endregion

#region User-defined Functions

public static Int32 GetWindowProcessID(IntPtr hwnd)
{
//This Function is used to get Active process ID...
Int32 pid;
GetWindowThreadProcessId(hwnd, out pid);
return pid;
}

public static IntPtr getforegroundWindow()
{
//This method is used to get Handle for Active Window using GetForegroundWindow() method present in user32.dll
return GetForegroundWindow();
}

public static string ActiveApplTitle()
{
//This method is used to get active application's title using GetWindowText() method present in user32.dll
IntPtr hwnd = getforegroundWindow();
if (hwnd.Equals(IntPtr.Zero)) return "";
string lpText = new string((char)0, 100);
int intLength = GetWindowText(hwnd, lpText, lpText.Length);
if ((intLength <= 0) || (intLength > lpText.Length)) return "unknown";
return lpText.Trim();
}

#endregion
}

A loggertől és az infoDelegate-től tekintsünk el, mindkettő csak a logolást segítette. Beregisztrálni és leregisztrálni a keylistenert a kódban, ahol ezt meg akarjuk tenni, a következőképp lehet:


Hook.CreateHook(new Hook.KeyHandler(filterLogic.filterEnterAndApp));


Hook.DestroyHook();
top