„Geomajas” változatai közötti eltérés
(Új oldal, tartalma: „Geomajas”) |
Mate (vitalap | szerkesztései) a |
||
(54 közbenső módosítás, amit 2 másik szerkesztő végzett, nincs mutatva) | |||
1. sor: | 1. sor: | ||
− | Geomajas | + | ==Áttekintés== |
+ | A Geomajas (http://www.geomajas.org/) egy Java nyelven íródott Open Source Web Mapping Framework. Mind szerver, mind kliensoldali komponenseket kínál. Szerveroldalon Java, Javascript, míg kliensoldalon Java (GWT) és Javascript nyelven tesz megvalósításokat elérhetővé. | ||
+ | |||
+ | A kliensoldal bár használható különálló módon, igazi hatékonyság és funkcióbőség a szerver és a kliens összehangolt működésével érhető el. | ||
+ | |||
+ | Főbb funkciók: | ||
+ | |||
+ | * Integrált szerver-kliens architektúra (Spring) | ||
+ | * Attribútum és geometria szerkesztés | ||
+ | * Egyedi attribútumdefiníció | ||
+ | * Magas szintű query lehetőségek (CQL) | ||
+ | * Bővíthető plugin mechanizmus | ||
+ | * Átfogó böngésző támogatás | ||
+ | * Biztonság (Token) | ||
+ | |||
+ | ==Előkészületek== | ||
+ | A mintaprogramok fordításához és futtatásához Maven-t használnak (https://maven.apache.org/). Ahhoz, hogy futtatni és fordítani tudjuk a github-os projekteket, a Maven telepítési könyvtárában a settings.xml-ben (HOME/.m2/settings.xml) fel kell venni néhány dependency-t, ez az xml a github-os gwt kliensnél megtalálható. (https://github.com/geomajas/geomajas-project-client-gwt2) | ||
+ | |||
+ | Kezdésként a GWT-s standalone applicationt indítsuk el, ez a következő linken érhető el. (https://github.com/geomajas/geomajas-gwt2-quickstart-application) Fordítsuk le a Mavennel a projektet, majd futtassuk. | ||
+ | |||
+ | <code> | ||
+ | mvn install | ||
+ | |||
+ | mvn jetty: run | ||
+ | </code> | ||
+ | |||
+ | Vagy egyben | ||
+ | <code>mvn install jetty: run</code> | ||
+ | |||
+ | Ezután látogassunk el a http://localhost:8080/-ra, ahol megtekinthető az eredmény. | ||
+ | ==Szerver oldal == | ||
+ | |||
+ | A Geomajas szerveroldali rész felelős az alkalmazás intergálhatóságért, célja a business logika integrálása GIS eszközökbe. A szerveroldalon konfigurálhatóak a layerek, térképek és a szolgáltatások. Bár sok megjelenítéssel kapcsolatos technológát (vektorgrafika, renderelés) tartalmaz, konkrét megjelenítéssel nem foglalkozik. A szolgáltatások dependecy injection-nel vannak összekötve, továbbá az inversion of controlnak hála a szerver nagyon rugalmas. | ||
+ | |||
+ | A Geomajas szerver oldal a Spring framework-öt használja. A szerver az alábbiakat nyújtja: | ||
+ | * Utasítások: Az utasítások elsődleges interakciós pontok a szerver és a kliens között. A szolgáltatások, térképek, layerek megkeresése mind utasításokkal történit. | ||
+ | * Layerek: Ezek tárolják a térképek tulajdonságaihoz a hozzáférési pontokat. Egy Layer lehet raszteres, vagy vektor alapú és szerkeszthető. A vektor layer részeit képező objektumok a "feature object"-ként érhetőek el, amit a Geomajas átkovertál számára használható formátumba, ezáltal nem kell interfaceket implementálni, minden POJO-k segítségével megoldható. Ezek a "feature"-ök tartalmazzák a geometriát és az attribútumok halmazát. Az attribútumok lehetnek komplexek: <code>@OneToMany</code> és <code>@ManyToOne</code> is. | ||
+ | * Pipeline-ok: Minden layerekkel foglalkozó Geomajas rész pipeline-okkal van megoldva. A pipeline-ok utasítások sorozatai, amelyek sorrendben hajtódnak végre. Habár minden layernek van default pipeline működése, ez felülírható. | ||
+ | * Biztonság: A biztonsági szolgáltatások közé tartozik a tokenes authentikáció, illetve a tokenhez tartozó hozzáféréssel elérhető objektumok megkeresése és visszatérése. Képes továbbá saját security ppolicy olvasására is. | ||
+ | |||
+ | A vektor layer és az <code>InternalFeautre</code> objektumai közötti konverziót a <code>FeatureModel</code> mondja meg. Ez a következőképpen néz ki: | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | @Api(allMethods = true) | ||
+ | @UserImplemented | ||
+ | public interface FeatureModel { | ||
+ | |||
+ | void setLayerInfo(VectorLayerInfo vectorLayerInfo) throws LayerException; | ||
+ | |||
+ | Attribute getAttribute(Object feature, String name) throws LayerException; | ||
+ | |||
+ | Map<String, Attribute> getAttributes(Object feature) throws LayerException; | ||
+ | |||
+ | String getId(Object feature) throws LayerException; | ||
+ | |||
+ | Geometry getGeometry(Object feature) throws LayerException; | ||
+ | |||
+ | void setAttributes(Object feature, java.util.Map<String, Attribute> attributes) throws LayerException; | ||
+ | |||
+ | void setGeometry(Object feature, Geometry geometry) throws LayerException; | ||
+ | |||
+ | Object newInstance() throws LayerException; | ||
+ | |||
+ | Object newInstance(String id) throws LayerException; | ||
+ | |||
+ | int getSrid() throws LayerException; | ||
+ | |||
+ | String getGeometryAttributeName() throws LayerException; | ||
+ | |||
+ | boolean canHandle(Object feature); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | A Geomajas POJO alapú, így nem vár komplex attribútumokat paraméterként, minden sima Java Object. Ez jól látható a vektor layer megvalósításában, amely az alábbi módon néz ki: | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | @Api(allMethods = true) | ||
+ | @UserImplemented | ||
+ | public interface VectorLayer extends Layer<VectorLayerInfo> { | ||
+ | |||
+ | boolean isCreateCapable(); | ||
+ | |||
+ | boolean isUpdateCapable(); | ||
+ | |||
+ | boolean isDeleteCapable(); | ||
+ | |||
+ | FeatureModel getFeatureModel(); | ||
+ | |||
+ | Object create(Object feature) throws LayerException; | ||
+ | |||
+ | Object saveOrUpdate(Object feature) throws LayerException; | ||
+ | |||
+ | Object read(String featureId) throws LayerException; | ||
+ | |||
+ | void delete(String featureId) throws LayerException; | ||
+ | |||
+ | Iterator<?> getElements(Filter filter, int offset, int maxResultSize) throws LayerException; | ||
+ | |||
+ | Envelope getBounds(Filter filter) throws LayerException; | ||
+ | |||
+ | Envelope getBounds() throws LayerException; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Sok esetben az információ eljuttatása a layer objektumokhoz szabályokat követ: | ||
+ | * Ha egy primitív attribútum változik meg egy új értékre, akkor ez az új érték lecseréli a régit. | ||
+ | * Bármely attribútum értéke ha <code>null</code>-ra állítódik, törlődik. | ||
+ | * Ha egy <code>@ManyToOne</code> attribútum értéke módosul egy létező objektumra, akkor az érték lecserélődik és az állapota frissül. | ||
+ | * Ha egy <code>@OneToMany</code> attribútum értéke <code>null</code>-ra, vagy üresre módosul, üres kollekció lesz belőle. Az így árván maradt objektumok törléséről, vagy megmaradásáról a <code>FeatureModel</code>-ben lehet nyilatkozni. | ||
+ | * Ha egy <code>@OneToMany</code> attribútum értéke egy új attribútum csoportra változik, akkor a meglévő attribútumok frissülnek, új attribútumok jönnek létre, a hiányzó értékekről pedig a <code>FeatureModel</code>-ben implementált viselkedés alkalmazódik. | ||
+ | * Az előző szabályok rekurzívan alkalmazhatóak. | ||
+ | |||
+ | Ezen szabályok betartására példa az <code>Entity</code> interface, amely az objektum-fák gráf összeillesztésénél játszik szerepet, ugyanis az összeillesztés megvalósítása nem a <code>FeatureModel</code>-ben található, hanem az <code>EntityAttributeService</code>-ben, amely feltételezi, hogy minden entitás megvalósítja a már említett interface-t. | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | @Api(allMethods = true) | ||
+ | @UserImplemented | ||
+ | public interface Entity { | ||
+ | |||
+ | Object getId(String name) throws LayerException; | ||
+ | |||
+ | Entity getChild(String name) throws LayerException; | ||
+ | |||
+ | void setChild(String name, Entity entity) throws LayerException; | ||
+ | |||
+ | EntityCollection getChildCollection(String name) throws LayerException; | ||
+ | |||
+ | void setAttribute(String name, Object value) throws LayerException; | ||
+ | |||
+ | Object getAttribute(String name) throws LayerException; | ||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Egy gyökérentitástól kezdve a <code>@OneToMany</code> és <code>@ManyToOne</code> kapcsolatok bejárhatóak a <code>getChild()</code> metódus segítségével. | ||
+ | |||
+ | ==A GWT quickstart application== | ||
+ | A GWT-s projekt általában egy gyökér könyvtárbeli szerver és kliens oldali csomagból áll. A kliens oldali belépési pontot az Application.java fájl tartalmazza, ami a következő helyen található: ..\geomajas-gwt2-quickstart-application-master\src\main\java\org\geomajas\quickstart\gwt2\client. | ||
+ | |||
+ | Ez megvalósítja a com.google.gwt.core.client.EntryPoint interfészt, így implementálni kell az onModuleLoad metódust. A kód egyszerű: létrejön egy ApplicationLayout, majd hozzáadódik a megjelenítéshez. | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | |||
+ | import com.google.gwt.core.client.EntryPoint; | ||
+ | import com.google.gwt.user.client.ui.RootLayoutPanel; | ||
+ | |||
+ | public class Application implements EntryPoint { | ||
+ | |||
+ | @Override | ||
+ | public void onModuleLoad() { | ||
+ | ApplicationLayout layout = new ApplicationLayout(); | ||
+ | RootLayoutPanel.get().add(layout); | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Az ApplicationLayout geomajas specifikus layout, a következő módon keletkezik: | ||
+ | |||
+ | <syntaxhighlight lang="java"> | ||
+ | public ApplicationLayout() { | ||
+ | initWidget(UIBINDER.createAndBindUi(this)); | ||
+ | ApplicationResource.INSTANCE.css().ensureInjected(); | ||
+ | |||
+ | mapPresenter = GeomajasImpl.getInstance().createMapPresenter(); | ||
+ | mapPresenter.getEventBus().addMapInitializationHandler(new MyMapInitializationHandler()); | ||
+ | |||
+ | GeomajasServerExtension.getInstance().initializeMap(mapPresenter, "app", "mapMain"); | ||
+ | |||
+ | mapLayoutPanel = new MapLayoutPanel(); | ||
+ | mapLayoutPanel.setPresenter(mapPresenter); | ||
+ | mapPanel.add(mapLayoutPanel); | ||
+ | |||
+ | appService = ApplicationService.getInstance(); | ||
+ | appService.setMapPresenter(mapPresenter); | ||
+ | appService.setMapLayoutPanel(mapLayoutPanel); | ||
+ | |||
+ | appService.getMapPresenter().getEventBus().addHandler(FeatureMouseOverHandler.TYPE, new MyFeatureMouseOverHandler()); | ||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Miután betöltődik a kontextusthoz szükséges GWT-s modul, létrejön egy MapPresenter, majd hozzá egy default inicializáló. Ezután a szerverkódból inicializáljuk ezt. Ezt követi a Layout beállítása, hozzáadása a megjelenítéshez, valamint egy ApplicationService létrehozása, amely kiszolgálja a ezt a Layert. Ezután hozzáadásra kerül egy egyedi eseménykezelő. | ||
+ | |||
+ | A quickstart application csak a gwt-s kliens egy részét tartalmazza, ezért használja a <code>GeomajasServerExtension</code>-t, a szerveroldal létező példánya helyett, viszont jó kiindulási pont a framework megismeréséhez. | ||
+ | |||
+ | == Javascript API == | ||
+ | A Client Javascript API a Client GWT-t használja. A Javascriptes projektnél a javadoc-os résznél elakad a maven, így csak az API és a gwt2 projekt fordítható le egyenként. A gwt2 projekt tartalma egy javascript api-t használó mintaalkalmazás, így elég csak ezt lefordítani. A dokumentációban említett gs.js fájlt azonban már nem generálja le, csak egy dinamikus azonosítóval ellátott js-t. | ||
+ | |||
+ | A Githubról a Javascript project (https://github.com/geomajas/geomajas-project-javascript) letöltése után, lefordíthatjuk a gwt2-es projektet, ami legenerálja a szükséges javascript fájlokat és létrehozza a megfelelő index.html-eket, mind szerver mind kliens oldalon. Az eredmény ideiglenesen a http://people.inf.elte.hu/bagtaai címen elérhető. Eredeti oldal, ami néha nem megy: (http://dev.geomajas.org/geomajas-project-javascript-gwt2-distribution-1.0.0-SNAPSHOT/). | ||
+ | |||
+ | A map betöltéséhez ez a modul egy <code>onGeomajasLoad</code> függvényt használ, ami lényegében az inicializációt hajtja végre. Az alábbi kódrészlet mutatja a legenerált index.html-ben szereplő példát. | ||
+ | |||
+ | <syntaxhighlight lang="javascript"> | ||
+ | <script type="text/javascript"> | ||
+ | var map; | ||
+ | var WMS_BASE_URL = "http://apps.geomajas.org/geoserver/demo_world/ows"; | ||
+ | var wmsVersion = "1.3.0"; //default value | ||
+ | |||
+ | |||
+ | function onGeomajasLoad() { | ||
+ | var mapConfig = new gm.MapConfiguration(); | ||
+ | mapConfig.setCrs("EPSG:4326", "DEGREES"); | ||
+ | mapConfig.setMinimumResolution(2.1457672119140625E-5) | ||
+ | mapConfig.setMaxBounds(new gm.Bbox(-180, -90, 360, 180)); | ||
+ | |||
+ | // Map létrehozása és inicializálása | ||
+ | |||
+ | map = new gm.Map("js-map-element", mapConfig); | ||
+ | |||
+ | // Kiürítjük a map-et | ||
+ | map.getLayersModel().clear(); | ||
+ | |||
+ | var tileConfig = new gm.layer.TileConfiguration(256, 256, new gm.Coordinate(-180, -90), | ||
+ | map.getViewPort()); | ||
+ | var layerConfig = new gm.WmsLayerConfiguration(); | ||
+ | |||
+ | layerConfig.setBaseUrl(WMS_BASE_URL); | ||
+ | layerConfig.setFormat("image/png"); | ||
+ | layerConfig.setVersion(wmsVersion); | ||
+ | layerConfig.setLayers("demo_world:simplified_country_borders"); | ||
+ | layerConfig.setMinimumResolution(2.1457672119140625E-5); | ||
+ | layerConfig.setMaximumResolution(Number.MAX_VALUE); | ||
+ | |||
+ | // Létrehozunk egy WMS Layert és hozzáadjuk a maphez: | ||
+ | |||
+ | var wmsLayer = new gm.WmsLayer("Blue Marble", map, layerConfig, tileConfig); | ||
+ | wmsLayer.setMaxBounds(new gm.Bbox(-180, -90, 360, 360)); | ||
+ | map.getLayersModel().addLayer(wmsLayer); | ||
+ | } | ||
+ | </script> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | A térkép objektumhoz hozzárendelhetők események: az inicializációhoz, a térkép megszűnéséhez, vagy a térkép betöltéséhez. | ||
+ | |||
+ | <syntaxhighlight lang="javascript"> | ||
+ | //Maphez hozzárendelhető események | ||
+ | map.getEventBus().addLayerAddedHandler(function(event) { | ||
+ | // custom code; event contains the added layer | ||
+ | alert('layer added: ' + event.getAddedLayer().getTitle()); | ||
+ | }); | ||
+ | map.getEventBus().addLayerRemovedHandler(function(event) { | ||
+ | // custom code; event contains the removed layer | ||
+ | alert('layer removed: ' + event.getRemovedLayer().getTitle()); | ||
+ | }); | ||
+ | map.getEventBus().addMapInitializationHandler(function(event) { | ||
+ | // custom code | ||
+ | alert('map fully initialized'); | ||
+ | }); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | A térkép objektumhoz hozzárendelhetők eseménykezelők, ezek közül az előre definiáltak: | ||
+ | *<code>'navigation'</code>-el elérhető a NavigationController, | ||
+ | *<code>'zoomToRectangle'</code>-el elérhető a ZoomToRectangleController, | ||
+ | *<code>'featureSelectionDrag'</code>-al a FeatureSelectionController érhető el a <code>SelectionMethod.CLICK_AND_DRAG</code>-el együtt, | ||
+ | *<code>'featureSelectionSingle'</code>-el elérhető a FeatureSelectionController a <code>SelectionMethod.SINGLE_SELECTION</code>-el. | ||
+ | |||
+ | Hozzáadni az alábbi módon tudunk: | ||
+ | |||
+ | <syntaxhighlight lang="javascript"> | ||
+ | map.setMapController(gm.MapControllerFactory.createMapController("default_kontroller_neve")); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Van lehetőség saját <code>MapController</code> létrehozására is: | ||
+ | |||
+ | <syntaxhighlight lang="javascript"> | ||
+ | // Üres kontroller létrehozása | ||
+ | var customMapController = gm.MapControllerFactory.createMapController(); | ||
+ | |||
+ | // Egyedi egérmozgás kezelő: | ||
+ | customMapController.setMouseMoveHandler(function(event) { | ||
+ | |||
+ | var screenLocation = mapController.getLocation(event, "screen"); | ||
+ | var worldLocation = mapController.getLocation(event, "world"); | ||
+ | var screenLocationAsText = "Screen: " + screenLocation.getX() + ", " + screenLocation.getY(); | ||
+ | var worldLocationAsText = "World: " + worldLocation.getX() + ", " + worldLocation.getY(); | ||
+ | |||
+ | }); | ||
+ | // Egyéb események, amelyek: | ||
+ | //setMouseOverHandler | ||
+ | //setMouseOutHandler | ||
+ | //setDownHandler | ||
+ | //setUpHandler | ||
+ | //setDragHandler | ||
+ | //setDoubleClickHandler | ||
+ | |||
+ | // Kontrollerre köthető események (activation, deactivation): | ||
+ | customMapController.setActivationHandler(function() { | ||
+ | |||
+ | alert('Custom controller activated!') | ||
+ | }); | ||
+ | //setDeactivationHandler | ||
+ | |||
+ | // MapController hozzáadása a térképhez: | ||
+ | map.setMapController(customMapController); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | A layerekhez különböző funkciók társíthatóak, amelyek a <code>FeatureSearchService</code> segítségével érhetőek el. | ||
+ | <syntaxhighlight lang="javascript"> | ||
+ | var service = map.getFeatureSearchService(); | ||
+ | // A layer egy specifikus műveletének lekérése | ||
+ | service.searchById(layer, [id], function(featureHolder){ | ||
+ | var feature = featureHolder.getFeatures()[0]; | ||
+ | alert("Feature found: " + feature.getLabel()); | ||
+ | }); | ||
+ | // összes művelet megkeresése | ||
+ | service.searchInBounds(layer, bounds, function(features) { | ||
+ | alert("Features found: " + featureHolder.getFeatures().size()); | ||
+ | }); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==A Geomajas és a Geosparc== | ||
+ | |||
+ | A geomajas mostanra a geosparc (http://www.geosparc.com/) alapja lett, amivel egyedi webes GIS alkalmazásokat készítenek. | ||
+ | |||
+ | ==Hibák== | ||
+ | A Quickstart application mavenes fordítása és futtatása probléma nélkül megtörtént, azonban a client-gwt2, és a szerveroldali projekt fordítása korántsem volt zökkenőmentes. A javascriptes projekt a javadoc generálásánál elszáll, egyenként az api és a gwt2 projekt rész lefordítható. | ||
+ | |||
+ | ===Checkstyle=== | ||
+ | A checkstyle egy kódformázó plugin, amit a régebbi eclipsekben használtak, azonban az újakban már eleve benne van. Kezdetben a plugin (https://maven.apache.org/plugins/maven-checkstyle-plugin/) verzióját nem találta meg a maven, ezt orvosolta a fejlesztők levelezéséből kiderített client-gwt2 projektben található settings.xml megfelelő helyre történő átmozgatása. | ||
+ | |||
+ | ===FirefoxBinary=== | ||
+ | A kliensoldali kód azonban így sem fordult le, a tesztek futtatásakor a selenium (http://www.seleniumhq.org/) plugin nem tudta elérni a FirefoxBinary-t és nem tudta lefuttatni a hozzá tartozó részeket. Ezt orvosolta a <code> mvn install -DskipTests </code> utasítás, ami a teszteket kihagyva képes sikeres fordítást produkálni. | ||
+ | |||
+ | ===Javadoc=== | ||
+ | Valamilyen oknál fogva a java, a régebbi javadocos kódrészleteket nem tudja értelmezni a maven a projekteken belül és fordításnál szintaktikai hibát eredményez. A projektek szükséges részei ettől függetlenül egyenként is lefordíthatóak kisebb-nagyobb szerencsével. | ||
+ | |||
+ | ===JettyRunner és az eclipse=== | ||
+ | A geomajas fejlesztői oldalán leírtak alapján, a GWT kliens és szerver oldal, az eclipse segítségével is fordítható lett volna, azonban a GWT pluginnal felkonfigurált eclipse a projekt betöltését követően a JettyRunner jetty szerverkonfiguráció futtatásánál elszáll. Az eclipse marketplace-ről letölthető GWT-s pluginnal és az eredeti GWT-s toollal sem sikerült a JettyRunner hibamentes konfigurációja, amely futtatásánál a SpringFramewörk valamiyel nhiányzó layerre panaszkodik. | ||
+ | |||
+ | A fent említett paraméterekkel az eclipse neon.1, neon.2 és a neon.3, illetve a kepler-es verzión is kipróbálva ugyanez a hiba jelentkezett. A kísérlet, minek során a quickstart application fordítására tettem kísérletet, az eclipse a maven-es pom.xml-ben hibát talált, valószínűleg kompatibilitási okokból. | ||
+ | |||
+ | ===Maven-es mintaprojekt=== | ||
+ | A források között található régebbi dokumentációk egyikében hivatkozás van egy alap geomajas projekt létrehozására külső url-ről a maven segítségével, azonban a funkció már nem elérhető. | ||
+ | |||
+ | ===Eltérések a dokumentációktól=== | ||
+ | Sok helyen a dokumentációban hivatkozott komponensek nem léteznek, vagy nem elérhetőek. Legjobb példa a Javascriptes kliens kód, amely a dokumentáció alapján letölthető lenne a http://dev.geomajas.org/geomajas-project-javascript-gwt2-distribution-1.0.0-SNAPSHOT/ URL-ről. Ez tartalmazna egy gs.js-t és egy index.html-t. A githubról letölthető Javascript Client (https://github.com/geomajas/geomajas-project-javascript) distribution része ugyanezt a kódot generálja, vagy csak egy részét, ami működik azonban a dokumentációban említett elméletben geomajas javascript fájl helyett egy dinamikusan generált javascript keletkezik. Ez elindításkor nehezményezi a gs.js hiányát, azonban a dokumentációban szereplő példa részletek futtathatóak. | ||
+ | |||
+ | ==Forrás, Linkek== | ||
+ | |||
+ | A wiki oldal megírásához az alábbi oldalakat használtam: | ||
+ | * http://www.geomajas.org/geomajas - Geomajas weboldal. | ||
+ | * https://github.com/geomajas - Geomajas Github. | ||
+ | * http://www.geomajas.org/client-javascript/snapshot - Javascript Snapshot és kis konfigurálással működőképessé varázsolható dokumentáció. | ||
+ | * http://files.geomajas.org/maven/ - A régebbi Geomajas dokumentációk. | ||
+ | * http://mapservercloud.com:8080/geomajas/applications/tutorial/html/ - Működő bemutató a komponensekről. | ||
+ | * http://files.geomajas.org/documentation/geomajas-project-server/snapshot/geomajas-server-documenatation/html/master.html - Geomajas szerver oldal dokumentációja. | ||
+ | |||
+ | * http://www.gwtproject.org/ - GWT oldala a pluginekkel. | ||
+ | * https://maven.apache.org/ - Maven oldala, az utasításokkal, pom.xml felépítésével... | ||
+ | * http://www.geosparc.com/ - Geosparc hivatalos oldala | ||
+ | * Előadás és JS minta - [[Fájl:geomajas_JMDTDY.zip]] |
A lap jelenlegi, 2017. május 25., 10:33-kori változata
Tartalomjegyzék
Áttekintés
A Geomajas (http://www.geomajas.org/) egy Java nyelven íródott Open Source Web Mapping Framework. Mind szerver, mind kliensoldali komponenseket kínál. Szerveroldalon Java, Javascript, míg kliensoldalon Java (GWT) és Javascript nyelven tesz megvalósításokat elérhetővé.
A kliensoldal bár használható különálló módon, igazi hatékonyság és funkcióbőség a szerver és a kliens összehangolt működésével érhető el.
Főbb funkciók:
- Integrált szerver-kliens architektúra (Spring)
- Attribútum és geometria szerkesztés
- Egyedi attribútumdefiníció
- Magas szintű query lehetőségek (CQL)
- Bővíthető plugin mechanizmus
- Átfogó böngésző támogatás
- Biztonság (Token)
Előkészületek
A mintaprogramok fordításához és futtatásához Maven-t használnak (https://maven.apache.org/). Ahhoz, hogy futtatni és fordítani tudjuk a github-os projekteket, a Maven telepítési könyvtárában a settings.xml-ben (HOME/.m2/settings.xml) fel kell venni néhány dependency-t, ez az xml a github-os gwt kliensnél megtalálható. (https://github.com/geomajas/geomajas-project-client-gwt2)
Kezdésként a GWT-s standalone applicationt indítsuk el, ez a következő linken érhető el. (https://github.com/geomajas/geomajas-gwt2-quickstart-application) Fordítsuk le a Mavennel a projektet, majd futtassuk.
mvn install
mvn jetty: run
Vagy egyben
mvn install jetty: run
Ezután látogassunk el a http://localhost:8080/-ra, ahol megtekinthető az eredmény.
Szerver oldal
A Geomajas szerveroldali rész felelős az alkalmazás intergálhatóságért, célja a business logika integrálása GIS eszközökbe. A szerveroldalon konfigurálhatóak a layerek, térképek és a szolgáltatások. Bár sok megjelenítéssel kapcsolatos technológát (vektorgrafika, renderelés) tartalmaz, konkrét megjelenítéssel nem foglalkozik. A szolgáltatások dependecy injection-nel vannak összekötve, továbbá az inversion of controlnak hála a szerver nagyon rugalmas.
A Geomajas szerver oldal a Spring framework-öt használja. A szerver az alábbiakat nyújtja:
- Utasítások: Az utasítások elsődleges interakciós pontok a szerver és a kliens között. A szolgáltatások, térképek, layerek megkeresése mind utasításokkal történit.
- Layerek: Ezek tárolják a térképek tulajdonságaihoz a hozzáférési pontokat. Egy Layer lehet raszteres, vagy vektor alapú és szerkeszthető. A vektor layer részeit képező objektumok a "feature object"-ként érhetőek el, amit a Geomajas átkovertál számára használható formátumba, ezáltal nem kell interfaceket implementálni, minden POJO-k segítségével megoldható. Ezek a "feature"-ök tartalmazzák a geometriát és az attribútumok halmazát. Az attribútumok lehetnek komplexek:
@OneToMany
és@ManyToOne
is. - Pipeline-ok: Minden layerekkel foglalkozó Geomajas rész pipeline-okkal van megoldva. A pipeline-ok utasítások sorozatai, amelyek sorrendben hajtódnak végre. Habár minden layernek van default pipeline működése, ez felülírható.
- Biztonság: A biztonsági szolgáltatások közé tartozik a tokenes authentikáció, illetve a tokenhez tartozó hozzáféréssel elérhető objektumok megkeresése és visszatérése. Képes továbbá saját security ppolicy olvasására is.
A vektor layer és az InternalFeautre
objektumai közötti konverziót a FeatureModel
mondja meg. Ez a következőképpen néz ki:
@Api(allMethods = true)
@UserImplemented
public interface FeatureModel {
void setLayerInfo(VectorLayerInfo vectorLayerInfo) throws LayerException;
Attribute getAttribute(Object feature, String name) throws LayerException;
Map<String, Attribute> getAttributes(Object feature) throws LayerException;
String getId(Object feature) throws LayerException;
Geometry getGeometry(Object feature) throws LayerException;
void setAttributes(Object feature, java.util.Map<String, Attribute> attributes) throws LayerException;
void setGeometry(Object feature, Geometry geometry) throws LayerException;
Object newInstance() throws LayerException;
Object newInstance(String id) throws LayerException;
int getSrid() throws LayerException;
String getGeometryAttributeName() throws LayerException;
boolean canHandle(Object feature);
}
A Geomajas POJO alapú, így nem vár komplex attribútumokat paraméterként, minden sima Java Object. Ez jól látható a vektor layer megvalósításában, amely az alábbi módon néz ki:
@Api(allMethods = true)
@UserImplemented
public interface VectorLayer extends Layer<VectorLayerInfo> {
boolean isCreateCapable();
boolean isUpdateCapable();
boolean isDeleteCapable();
FeatureModel getFeatureModel();
Object create(Object feature) throws LayerException;
Object saveOrUpdate(Object feature) throws LayerException;
Object read(String featureId) throws LayerException;
void delete(String featureId) throws LayerException;
Iterator<?> getElements(Filter filter, int offset, int maxResultSize) throws LayerException;
Envelope getBounds(Filter filter) throws LayerException;
Envelope getBounds() throws LayerException;
}
Sok esetben az információ eljuttatása a layer objektumokhoz szabályokat követ:
- Ha egy primitív attribútum változik meg egy új értékre, akkor ez az új érték lecseréli a régit.
- Bármely attribútum értéke ha
null
-ra állítódik, törlődik. - Ha egy
@ManyToOne
attribútum értéke módosul egy létező objektumra, akkor az érték lecserélődik és az állapota frissül. - Ha egy
@OneToMany
attribútum értékenull
-ra, vagy üresre módosul, üres kollekció lesz belőle. Az így árván maradt objektumok törléséről, vagy megmaradásáról aFeatureModel
-ben lehet nyilatkozni. - Ha egy
@OneToMany
attribútum értéke egy új attribútum csoportra változik, akkor a meglévő attribútumok frissülnek, új attribútumok jönnek létre, a hiányzó értékekről pedig aFeatureModel
-ben implementált viselkedés alkalmazódik. - Az előző szabályok rekurzívan alkalmazhatóak.
Ezen szabályok betartására példa az Entity
interface, amely az objektum-fák gráf összeillesztésénél játszik szerepet, ugyanis az összeillesztés megvalósítása nem a FeatureModel
-ben található, hanem az EntityAttributeService
-ben, amely feltételezi, hogy minden entitás megvalósítja a már említett interface-t.
@Api(allMethods = true)
@UserImplemented
public interface Entity {
Object getId(String name) throws LayerException;
Entity getChild(String name) throws LayerException;
void setChild(String name, Entity entity) throws LayerException;
EntityCollection getChildCollection(String name) throws LayerException;
void setAttribute(String name, Object value) throws LayerException;
Object getAttribute(String name) throws LayerException;
}
Egy gyökérentitástól kezdve a @OneToMany
és @ManyToOne
kapcsolatok bejárhatóak a getChild()
metódus segítségével.
A GWT quickstart application
A GWT-s projekt általában egy gyökér könyvtárbeli szerver és kliens oldali csomagból áll. A kliens oldali belépési pontot az Application.java fájl tartalmazza, ami a következő helyen található: ..\geomajas-gwt2-quickstart-application-master\src\main\java\org\geomajas\quickstart\gwt2\client.
Ez megvalósítja a com.google.gwt.core.client.EntryPoint interfészt, így implementálni kell az onModuleLoad metódust. A kód egyszerű: létrejön egy ApplicationLayout, majd hozzáadódik a megjelenítéshez.
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootLayoutPanel;
public class Application implements EntryPoint {
@Override
public void onModuleLoad() {
ApplicationLayout layout = new ApplicationLayout();
RootLayoutPanel.get().add(layout);
}
}
Az ApplicationLayout geomajas specifikus layout, a következő módon keletkezik:
public ApplicationLayout() {
initWidget(UIBINDER.createAndBindUi(this));
ApplicationResource.INSTANCE.css().ensureInjected();
mapPresenter = GeomajasImpl.getInstance().createMapPresenter();
mapPresenter.getEventBus().addMapInitializationHandler(new MyMapInitializationHandler());
GeomajasServerExtension.getInstance().initializeMap(mapPresenter, "app", "mapMain");
mapLayoutPanel = new MapLayoutPanel();
mapLayoutPanel.setPresenter(mapPresenter);
mapPanel.add(mapLayoutPanel);
appService = ApplicationService.getInstance();
appService.setMapPresenter(mapPresenter);
appService.setMapLayoutPanel(mapLayoutPanel);
appService.getMapPresenter().getEventBus().addHandler(FeatureMouseOverHandler.TYPE, new MyFeatureMouseOverHandler());
}
Miután betöltődik a kontextusthoz szükséges GWT-s modul, létrejön egy MapPresenter, majd hozzá egy default inicializáló. Ezután a szerverkódból inicializáljuk ezt. Ezt követi a Layout beállítása, hozzáadása a megjelenítéshez, valamint egy ApplicationService létrehozása, amely kiszolgálja a ezt a Layert. Ezután hozzáadásra kerül egy egyedi eseménykezelő.
A quickstart application csak a gwt-s kliens egy részét tartalmazza, ezért használja a GeomajasServerExtension
-t, a szerveroldal létező példánya helyett, viszont jó kiindulási pont a framework megismeréséhez.
Javascript API
A Client Javascript API a Client GWT-t használja. A Javascriptes projektnél a javadoc-os résznél elakad a maven, így csak az API és a gwt2 projekt fordítható le egyenként. A gwt2 projekt tartalma egy javascript api-t használó mintaalkalmazás, így elég csak ezt lefordítani. A dokumentációban említett gs.js fájlt azonban már nem generálja le, csak egy dinamikus azonosítóval ellátott js-t.
A Githubról a Javascript project (https://github.com/geomajas/geomajas-project-javascript) letöltése után, lefordíthatjuk a gwt2-es projektet, ami legenerálja a szükséges javascript fájlokat és létrehozza a megfelelő index.html-eket, mind szerver mind kliens oldalon. Az eredmény ideiglenesen a http://people.inf.elte.hu/bagtaai címen elérhető. Eredeti oldal, ami néha nem megy: (http://dev.geomajas.org/geomajas-project-javascript-gwt2-distribution-1.0.0-SNAPSHOT/).
A map betöltéséhez ez a modul egy onGeomajasLoad
függvényt használ, ami lényegében az inicializációt hajtja végre. Az alábbi kódrészlet mutatja a legenerált index.html-ben szereplő példát.
<script type="text/javascript">
var map;
var WMS_BASE_URL = "http://apps.geomajas.org/geoserver/demo_world/ows";
var wmsVersion = "1.3.0"; //default value
function onGeomajasLoad() {
var mapConfig = new gm.MapConfiguration();
mapConfig.setCrs("EPSG:4326", "DEGREES");
mapConfig.setMinimumResolution(2.1457672119140625E-5)
mapConfig.setMaxBounds(new gm.Bbox(-180, -90, 360, 180));
// Map létrehozása és inicializálása
map = new gm.Map("js-map-element", mapConfig);
// Kiürítjük a map-et
map.getLayersModel().clear();
var tileConfig = new gm.layer.TileConfiguration(256, 256, new gm.Coordinate(-180, -90),
map.getViewPort());
var layerConfig = new gm.WmsLayerConfiguration();
layerConfig.setBaseUrl(WMS_BASE_URL);
layerConfig.setFormat("image/png");
layerConfig.setVersion(wmsVersion);
layerConfig.setLayers("demo_world:simplified_country_borders");
layerConfig.setMinimumResolution(2.1457672119140625E-5);
layerConfig.setMaximumResolution(Number.MAX_VALUE);
// Létrehozunk egy WMS Layert és hozzáadjuk a maphez:
var wmsLayer = new gm.WmsLayer("Blue Marble", map, layerConfig, tileConfig);
wmsLayer.setMaxBounds(new gm.Bbox(-180, -90, 360, 360));
map.getLayersModel().addLayer(wmsLayer);
}
</script>
A térkép objektumhoz hozzárendelhetők események: az inicializációhoz, a térkép megszűnéséhez, vagy a térkép betöltéséhez.
//Maphez hozzárendelhető események
map.getEventBus().addLayerAddedHandler(function(event) {
// custom code; event contains the added layer
alert('layer added: ' + event.getAddedLayer().getTitle());
});
map.getEventBus().addLayerRemovedHandler(function(event) {
// custom code; event contains the removed layer
alert('layer removed: ' + event.getRemovedLayer().getTitle());
});
map.getEventBus().addMapInitializationHandler(function(event) {
// custom code
alert('map fully initialized');
});
A térkép objektumhoz hozzárendelhetők eseménykezelők, ezek közül az előre definiáltak:
'navigation'
-el elérhető a NavigationController,'zoomToRectangle'
-el elérhető a ZoomToRectangleController,'featureSelectionDrag'
-al a FeatureSelectionController érhető el aSelectionMethod.CLICK_AND_DRAG
-el együtt,'featureSelectionSingle'
-el elérhető a FeatureSelectionController aSelectionMethod.SINGLE_SELECTION
-el.
Hozzáadni az alábbi módon tudunk:
map.setMapController(gm.MapControllerFactory.createMapController("default_kontroller_neve"));
Van lehetőség saját MapController
létrehozására is:
// Üres kontroller létrehozása
var customMapController = gm.MapControllerFactory.createMapController();
// Egyedi egérmozgás kezelő:
customMapController.setMouseMoveHandler(function(event) {
var screenLocation = mapController.getLocation(event, "screen");
var worldLocation = mapController.getLocation(event, "world");
var screenLocationAsText = "Screen: " + screenLocation.getX() + ", " + screenLocation.getY();
var worldLocationAsText = "World: " + worldLocation.getX() + ", " + worldLocation.getY();
});
// Egyéb események, amelyek:
//setMouseOverHandler
//setMouseOutHandler
//setDownHandler
//setUpHandler
//setDragHandler
//setDoubleClickHandler
// Kontrollerre köthető események (activation, deactivation):
customMapController.setActivationHandler(function() {
alert('Custom controller activated!')
});
//setDeactivationHandler
// MapController hozzáadása a térképhez:
map.setMapController(customMapController);
A layerekhez különböző funkciók társíthatóak, amelyek a FeatureSearchService
segítségével érhetőek el.
var service = map.getFeatureSearchService();
// A layer egy specifikus műveletének lekérése
service.searchById(layer, [id], function(featureHolder){
var feature = featureHolder.getFeatures()[0];
alert("Feature found: " + feature.getLabel());
});
// összes művelet megkeresése
service.searchInBounds(layer, bounds, function(features) {
alert("Features found: " + featureHolder.getFeatures().size());
});
A Geomajas és a Geosparc
A geomajas mostanra a geosparc (http://www.geosparc.com/) alapja lett, amivel egyedi webes GIS alkalmazásokat készítenek.
Hibák
A Quickstart application mavenes fordítása és futtatása probléma nélkül megtörtént, azonban a client-gwt2, és a szerveroldali projekt fordítása korántsem volt zökkenőmentes. A javascriptes projekt a javadoc generálásánál elszáll, egyenként az api és a gwt2 projekt rész lefordítható.
Checkstyle
A checkstyle egy kódformázó plugin, amit a régebbi eclipsekben használtak, azonban az újakban már eleve benne van. Kezdetben a plugin (https://maven.apache.org/plugins/maven-checkstyle-plugin/) verzióját nem találta meg a maven, ezt orvosolta a fejlesztők levelezéséből kiderített client-gwt2 projektben található settings.xml megfelelő helyre történő átmozgatása.
FirefoxBinary
A kliensoldali kód azonban így sem fordult le, a tesztek futtatásakor a selenium (http://www.seleniumhq.org/) plugin nem tudta elérni a FirefoxBinary-t és nem tudta lefuttatni a hozzá tartozó részeket. Ezt orvosolta a mvn install -DskipTests
utasítás, ami a teszteket kihagyva képes sikeres fordítást produkálni.
Javadoc
Valamilyen oknál fogva a java, a régebbi javadocos kódrészleteket nem tudja értelmezni a maven a projekteken belül és fordításnál szintaktikai hibát eredményez. A projektek szükséges részei ettől függetlenül egyenként is lefordíthatóak kisebb-nagyobb szerencsével.
JettyRunner és az eclipse
A geomajas fejlesztői oldalán leírtak alapján, a GWT kliens és szerver oldal, az eclipse segítségével is fordítható lett volna, azonban a GWT pluginnal felkonfigurált eclipse a projekt betöltését követően a JettyRunner jetty szerverkonfiguráció futtatásánál elszáll. Az eclipse marketplace-ről letölthető GWT-s pluginnal és az eredeti GWT-s toollal sem sikerült a JettyRunner hibamentes konfigurációja, amely futtatásánál a SpringFramewörk valamiyel nhiányzó layerre panaszkodik.
A fent említett paraméterekkel az eclipse neon.1, neon.2 és a neon.3, illetve a kepler-es verzión is kipróbálva ugyanez a hiba jelentkezett. A kísérlet, minek során a quickstart application fordítására tettem kísérletet, az eclipse a maven-es pom.xml-ben hibát talált, valószínűleg kompatibilitási okokból.
Maven-es mintaprojekt
A források között található régebbi dokumentációk egyikében hivatkozás van egy alap geomajas projekt létrehozására külső url-ről a maven segítségével, azonban a funkció már nem elérhető.
Eltérések a dokumentációktól
Sok helyen a dokumentációban hivatkozott komponensek nem léteznek, vagy nem elérhetőek. Legjobb példa a Javascriptes kliens kód, amely a dokumentáció alapján letölthető lenne a http://dev.geomajas.org/geomajas-project-javascript-gwt2-distribution-1.0.0-SNAPSHOT/ URL-ről. Ez tartalmazna egy gs.js-t és egy index.html-t. A githubról letölthető Javascript Client (https://github.com/geomajas/geomajas-project-javascript) distribution része ugyanezt a kódot generálja, vagy csak egy részét, ami működik azonban a dokumentációban említett elméletben geomajas javascript fájl helyett egy dinamikusan generált javascript keletkezik. Ez elindításkor nehezményezi a gs.js hiányát, azonban a dokumentációban szereplő példa részletek futtathatóak.
Forrás, Linkek
A wiki oldal megírásához az alábbi oldalakat használtam:
- http://www.geomajas.org/geomajas - Geomajas weboldal.
- https://github.com/geomajas - Geomajas Github.
- http://www.geomajas.org/client-javascript/snapshot - Javascript Snapshot és kis konfigurálással működőképessé varázsolható dokumentáció.
- http://files.geomajas.org/maven/ - A régebbi Geomajas dokumentációk.
- http://mapservercloud.com:8080/geomajas/applications/tutorial/html/ - Működő bemutató a komponensekről.
- http://files.geomajas.org/documentation/geomajas-project-server/snapshot/geomajas-server-documenatation/html/master.html - Geomajas szerver oldal dokumentációja.
- http://www.gwtproject.org/ - GWT oldala a pluginekkel.
- https://maven.apache.org/ - Maven oldala, az utasításokkal, pom.xml felépítésével...
- http://www.geosparc.com/ - Geosparc hivatalos oldala
- Előadás és JS minta - Fájl:Geomajas JMDTDY.zip