{"id":46705,"date":"2015-10-12T10:00:18","date_gmt":"2015-10-12T07:00:18","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=46705"},"modified":"2015-10-11T13:10:54","modified_gmt":"2015-10-11T10:10:54","slug":"openmap-tutorial-part-1","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html","title":{"rendered":"OpenMap Tutorial &#8211; Part 1"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>This series of tutorials will show you how to build Java applications using the <a href=\"http:\/\/openmap-java.org\/\">OpenMap<\/a> GIS Java Swing library.<\/p>\n<p>OpenMap&#8217;s Developer <a href=\"http:\/\/openmap-java.org\/docs\/OpenMapDevGuide.pdf\">guide<\/a> is a very useful document that describes OpenMap&#8217;s architecture but it doesn&#8217;t explain how to start and build up an application step-by-step. The examples that come together with the source code are useful but not enough.<\/p>\n<p>OpenMap is written in Swing. As of this writing the latest version is 5.1.12. You can download both source code and executable jars from <a href=\"https:\/\/github.com\/openmap-java\/openmap\">GitHub<\/a>. Once you copy\/unzip\/clone it to a directory, you can execute it by either running the relevant script for your platform (<code>openmap.bat<\/code> or <code>openmap<\/code>) or by double clicking on <code>lib\/openmap.jar<\/code>. You should see a full GIS application like the one in Figure 1. We will try to build a similar application by the end of this series. The OpenMap source code also contains some examples of how to use OpenMap. In this tutorial we shall be based on <code>com.bbn.openmap.app.example.SimpleMap<\/code>. In the second tutorial we will be using code from <code>com.bbn.openmap.app.example.SimpleMap2<\/code>. Later tutorials will be based on other examples.<\/p>\n<p>In this series of tutorials we shall use the latest <a href=\"http:\/\/netbeans.org\/\">NetBeans<\/a> IDE 8.1 to create our applications.<\/p>\n<h2>Tutorial 1 \u2013 Build a basic map application<\/h2>\n<h3>Create a JFrame application<\/h3>\n<p>In this first tutorial we shall build a basic <code>JFrame <\/code>application that contains a map (see Figure 2). Open NetBeans and create a new Java application by following these steps:<\/p>\n<ol>\n<li>Open menu <strong>File \u2192 New Project<\/strong> and select <em>Category<\/em>: <strong>Java <\/strong>and <em>Project<\/em>: <strong>Java Application <\/strong>(Figure 3). Click <strong>Next<\/strong>.<\/li>\n<li>In the next step, provide a name and a location. Make sure you use a dedicated folder for the libraries and that you don&#8217;t select a main class (Figure 4). Click on <strong>Finish<\/strong>.<\/li>\n<li>Once your new project has been created, create a new package named <code>openmap <\/code>by right-clicking on <em>Source Packages<\/em> and selecting <strong>New \u2192 Java Package<\/strong> from the popup menu.<\/li>\n<li>Right-click on <strong>Libraries<\/strong> folder and select the action <strong>Add JAR\/Folder<\/strong> from the popup menu. Navigate to the <code>lib <\/code>folder of your <em>OpenMap<\/em> installation and select <code>openmap.jar<\/code>. You can use a relative path or better copy it to your <em>Libraries<\/em> folder (Figure 5). Click on <strong>Open<\/strong> to close the dialog box!<br \/>\n&nbsp;<br \/>\n<figure id=\"attachment_46711\" aria-describedby=\"caption-attachment-46711\" style=\"width: 656px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic1.png\"><img decoding=\"async\" class=\"size-full wp-image-46711\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic1.png\" alt=\"Figure 1: The OpenMap GIS application window\" width=\"656\" height=\"603\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic1.png 656w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic1-300x276.png 300w\" sizes=\"(max-width: 656px) 100vw, 656px\" \/><\/a><figcaption id=\"caption-attachment-46711\" class=\"wp-caption-text\">Figure 1: The OpenMap GIS application window<\/figcaption><\/figure><\/li>\n<li>You also need to copy the map files. The most common format is <code>.shp<\/code> (ESRI Shape). Create a new folder hierarchy<code> resources\/map<\/code> by selecting the <em>Files<\/em> window in NetBeans, right-clicking on <code>OpenMap1<\/code> project and selecting <strong>New \u2192 Folder<\/strong> from the popup menu. Enter the name <code>resources <\/code>and click on <strong>OK<\/strong>. Right-click on the <code>resources <\/code>folder and repeat the procedure to create the map folder inside it. Copy <code>share\/data\/shape<\/code> folder from your <em>OpenMap<\/em> installation to the <code>map<\/code> folder<\/li>\n<li>Create a new <code>JFrame <\/code>form by right-clicking on the <code>openmap <\/code>package and selecting <strong>New \u2192 JFrame Form<\/strong> from the popup menu. Give it a name, e.g. <strong>MapFrame<\/strong> and click on <strong>Finish<\/strong>.<br \/>\n&nbsp;<br \/>\n<figure id=\"attachment_46712\" aria-describedby=\"caption-attachment-46712\" style=\"width: 640px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic2.png\"><img decoding=\"async\" class=\"size-full wp-image-46712\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic2.png\" alt=\"A Basic OpenMap Swing application\" width=\"640\" height=\"480\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic2.png 640w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic2-300x225.png 300w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/a><figcaption id=\"caption-attachment-46712\" class=\"wp-caption-text\">A Basic OpenMap Swing application<\/figcaption><\/figure><\/li>\n<li>Click on <strong>Source<\/strong> button to see the generated code (see Listing 1).<\/li>\n<li>Add the line <code>super(\"Simple Map\"); <\/code> in the constructor to set the window title.<\/li>\n<li>The constructor initialises the <code>JFrame<\/code>. Nothing is added to it so far. Since it is a GUI application, it needs to run in the EDT thread, and this is what NetBeans has written in the <code>main()<\/code> method for us.<\/li>\n<li>Click back on <strong>Design<\/strong> button to see the empty form.<\/li>\n<\/ol>\n<p>We can add <em>OpenMap<\/em> JavaBeans to the Palette. To do that:<\/p>\n<ol start=\"11\">\n<li>Right-click on the palette and select <strong>Palette Manager<\/strong>.<\/li>\n<li>Click on <strong>New Category<\/strong> and enter <em>OpenMap <\/em>as the category name. Click Click on <strong>Add from JAR <\/strong>button, navigate to the <code>openmap.jar<\/code><strong>,<\/strong> select the <strong>Show All JavaBeans<\/strong> radio button and select all available components. Click <strong>Next.<\/strong><\/li>\n<li>Select the <em>OpenMap<\/em> palette category and click on <strong>Finish<\/strong>. A new palette category has been added to the Palette.<br \/>\n&nbsp;<br \/>\n<figure id=\"attachment_46713\" aria-describedby=\"caption-attachment-46713\" style=\"width: 737px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic3.png\"><img decoding=\"async\" class=\"size-full wp-image-46713\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic3.png\" alt=\"3: Create a new Java application\" width=\"737\" height=\"507\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic3.png 737w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic3-300x206.png 300w\" sizes=\"(max-width: 737px) 100vw, 737px\" \/><\/a><figcaption id=\"caption-attachment-46713\" class=\"wp-caption-text\">3: Create a new Java application<\/figcaption><\/figure><\/li>\n<\/ol>\n<h3>Add the map<\/h3>\n<ol start=\"14\">\n<li>Locate the <code>MapBean <\/code>and drag it to the <code>MapFrame<\/code>.<\/li>\n<li>In the <em>Navigator<\/em> window of NetBeans, right-click <code>mapBean1<\/code>, select <strong>Change Variable Name<\/strong> and set it to <code>mapBean<\/code>.<\/li>\n<li>In the <em>Navigator<\/em> window, right-click on <code>JFrame <\/code>and change its layout to <code>BorderLayout<\/code><\/li>\n<li>The resulting code is shown in Listing 2.<br \/>\n&nbsp;<br \/>\n<figure id=\"attachment_46714\" aria-describedby=\"caption-attachment-46714\" style=\"width: 737px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic4.png\"><img decoding=\"async\" class=\"size-full wp-image-46714\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic4.png\" alt=\"FFigure 4: Provide a Project name and location\" width=\"737\" height=\"411\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic4.png 737w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic4-300x167.png 300w\" sizes=\"(max-width: 737px) 100vw, 737px\" \/><\/a><figcaption id=\"caption-attachment-46714\" class=\"wp-caption-text\">FFigure 4: Provide a Project name and location<\/figcaption><\/figure><\/li>\n<\/ol>\n<p>&nbsp;<br \/>\n<figure id=\"attachment_46715\" aria-describedby=\"caption-attachment-46715\" style=\"width: 719px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic5.png\"><img decoding=\"async\" class=\"size-full wp-image-46715\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic5.png\" alt=\"Figure 5: Add openmap.jar to your Libraries folder\" width=\"719\" height=\"399\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic5.png 719w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2015\/10\/OpenMap_Pic5-300x166.png 300w\" sizes=\"(max-width: 719px) 100vw, 719px\" \/><\/a><figcaption id=\"caption-attachment-46715\" class=\"wp-caption-text\">Figure 5: Add openmap.jar to your Libraries folder<\/figcaption><\/figure><\/p>\n<p>The <code>com.bbn.openmap.MapBean <\/code>component is the main map window component in the <em>OpenMap<\/em> toolkit. The <code>MapBean <\/code>derives from the <code>java.awt.Container<\/code> class. Because it is a Swing component, it can be added to a Java window hierarchy like any other user interface component.<\/p>\n<p>To create the map in the <code>MapBean<\/code>, <code>Layers (com.bbn.openmap.Layer)<\/code> are added to the <code>MapBean<\/code>. Layers derive from <code>java.awt.Component<\/code> and they are the only components that can be added to a MapBean. Because <code>Layers <\/code>are <code>Components <\/code>contained within a <code>MapBean <\/code>container, the rendering of <code>Layers <\/code>onto the map is controlled by the Java component rendering mechanism. This mechanism controls how layered components are painted on top of each other. To make sure that each component gets painted into the window in the proper order, the <code>Component <\/code>class includes a method that allows it to tell the rendering mechanism that it would like to be painted. This feature allows <code>Layers <\/code>to work independently from each other, and lets the <code>MapBean <\/code>avoid knowing what is happening on the Layers.<\/p>\n<p><em><strong>Listing 1: Basic Swing application<\/strong><\/em><\/p>\n<pre class=\"brush:java\">public class MapFrame extends javax.swing.JFrame {\r\n\r\n   \/** Creates new form MapFrame *\/\r\n   public MapFrame() {\r\n      super(\"Simple Map\");\r\n      initComponents();\r\n   }\r\n\r\n  @SuppressWarnings(\"unchecked\")\r\n   \/\/ &lt;editor-fold defaultstate=\"collapsed\" desc=\"Generated Code\"&gt;                          \r\n   private void initComponents() {\r\n     \/\/ Content suppressed\r\n   }  \r\n\r\n   \/**\r\n    * @param args the command line arguments\r\n    *\/\r\n   public static void main(String args[]) {\r\n      \r\n      \/* Create and display the form *\/\r\n      java.awt.EventQueue.invokeLater(new Runnable() {\r\n         @Override\r\n         public void run() {\r\n            new MapFrame().setVisible(true);\r\n         }\r\n      });\r\n   }\r\n}\r\n<\/pre>\n<p><em><strong>Listing 2: Add a MapBean<\/strong><\/em><div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<pre class=\"brush:java\">  @SuppressWarnings(\"unchecked\")\r\n   \/\/ &lt;editor-fold defaultstate=\"collapsed\" desc=\"Generated Code\"&gt;                          \r\n   private void initComponents() {\r\n     mapBean = new com.bbn.openmap.MapBean();\r\n setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);\r\n      getContentPane().add(mapBean, java.awt.BorderLayout.CENTER);\r\n\r\n      pack();\r\n   }  \r\n<\/pre>\n<p><em><strong>Listing 3: Add a ShapeLayer to the MapBean<\/strong><\/em><\/p>\n<pre class=\"brush:java\">\/**\r\n  * Create a ShapeLayer to show world political boundaries. Set the properties of the layer. This assumes that\r\n  * the datafiles {@code dcwpo-browse.shp} and {@code dcwpo-browse.ssx} are in a path specified in the CLASSPATH variable.\r\n  * These files are distributed with OpenMap and reside in the toplevel \"share\" subdirectory.\r\n  *\/\r\nprivate void initMap() {\r\n      Properties shapeLayerProps = new Properties();\r\n      shapeLayerProps.put(\"prettyName\", \"Political Solid\");\r\n      shapeLayerProps.put(\"lineColor\", \"000000\");\r\n      shapeLayerProps.put(\"fillColor\", \"BDDE83\");\r\n      shapeLayerProps.put(\"shapeFile\", \"resources\/map\/shape\/dcwpo-browse.shp\");\r\n      shapeLayerProps.put(\"spatialIndex\", \"resources\/map\/shape\/dcwpo-browse.ssx\");\r\n\r\n      ShapeLayer shapeLayer = new ShapeLayer();\r\n      shapeLayer.setProperties(shapeLayerProps);\r\n\r\n      \/\/ Add the political layer to the map\r\n      mapBean.add(shapeLayer);\r\n}\r\n\r\n<\/pre>\n<p>Layers in an OpenMap application can use data from many sources:<\/p>\n<ul>\n<li>By computing them<\/li>\n<li>From data files of a local hard drive.<\/li>\n<li>From data files from a URL.<\/li>\n<li>From data files contained in a jar file.<\/li>\n<li>Using information retrieved from a database (JDBC).<\/li>\n<li>Using information received from a map server (images or map objects).<\/li>\n<\/ul>\n<ol>\n<li>Listing 3 shows a new method <code>initMap() <\/code>added in the constructor of <code>MapFrame <\/code> after <code>initComponents()<\/code> which shows how to add a <code>ShapeLayer<\/code> to the <code>MapBean<\/code> in order to render a map of political borders retrieved from <code>shape (.shp)<\/code> files. Right-click on <code>MapFrame<\/code> class and select <strong>Run File<\/strong>. You should see the window of Figure 2. Well done.\n<p>The <em>OpenMap<\/em> application is configured with an <code>openmap.properties file<\/code>. The contents of this file specify which components are created and added to the application framework, including layers. Applications can be configured without recompilation, simply by modifying the o<code>penmap.properties<\/code> file with a text editor. Components that have be written with an understanding of the framework can be added to the application simply by making additions to the above properties file. Components written to use properties will be given their settings in order to initialize themselves properly. Layers that rely on the location of data files or servers, for example, usually have properties that let those locations be set at run-time. This properties file is usually located either in the application folder or better to the user&#8217;s home folder. In the later case, each user can customize the application to their needs.<\/p>\n<p>Let&#8217;s move the properties for the shape layer to a properties file and read them from there.<\/li>\n<\/ol>\n<ol start=\"2\">\n<li>Right-click on <em>OpenMap<\/em> project and select <strong>New \u2192 Properties File<\/strong> from the popup menu. Give it the name properties and click on <strong>Finish<\/strong>.<\/li>\n<li>You can view this file in the <em>Projects<\/em> window, show click on the <em>Files<\/em> window and double click on it to open it in the NetBeans editor.<\/li>\n<li>Paste the contents of Listing 4.<\/li>\n<li>Comment out the lines where the properties of the shape layer are set in <code>initMap()<\/code> method and replace them with the code of Listing 5.<\/li>\n<li>Run the application again to see the exact same window (Figure 2).<em><strong>Listing 4: openmap.properties<\/strong><\/em>\n<pre class=\"brush:java\">prettyName=Political Solid\r\nlineColor=000000\r\nfillColor=BDDE83\r\nshapeFile=resources\/map\/shape\/dcwpo-browse.shp\r\nspatialIndex=resources\/map\/shape\/dcwpo-browse.ssx\r\n<\/pre>\n<p><em>OpenMap<\/em> provides a special class to handle properties. <code>com.bbn.openmap.PropertyHandler<\/code> is a component that uses an <code>openmap.properties<\/code> file to configure an application. It can be told which file to read properties from, or left to its own to find an <code>openmap.properties<\/code> file in the Java classpath and in the application user\u2019s home directory.<\/p>\n<p><em><strong>Listing 5: initMap() contents<\/strong><\/em><\/p>\n<pre class=\"brush:java\">      InputStream is = null;\r\n      try {\r\n         is = new FileInputStream(\"openmap.properties\");\r\n         shapeLayerProps.load(is);\r\n      } catch (FileNotFoundException ex) {\r\n         Logger.getLogger(OpenMap.class.getName()).log(Level.SEVERE, null, ex);\r\n      } catch (IOException ex) {\r\n         Logger.getLogger(OpenMap.class.getName()).log(Level.SEVERE, null, ex);\r\n      } finally {\r\n         if (is != null) {\r\n            try {\r\n               is.close();\r\n            } catch (IOException ex) {\r\n              Logger.getLogger(OpenMap.class.getName()).log(Level.SEVERE, null, ex);\r\n            }\r\n         }\r\n      }\r\n<\/pre>\n<\/li>\n<\/ol>\n<ol start=\"7\">\n<li>Listing 6 shows the updated <code>initMap()<\/code> You don&#8217;t need a <code>Properties <\/code>instance anymore. Just make sure that you tell <code>PropertyHandler.Builder()<\/code> to use the <code>openmap.properties<\/code> in the local directory (a.k.a. .\/openmap.properties) otherwise it might pick-up one from the user&#8217;s home directory or another location. Of course, <code>PropertyHandler <\/code>can do much more than this as we shall see in future tutorials.<em><strong>Listing 6: initMap() contents using a PropertyHandler<\/strong><\/em>\n<pre class=\"brush:java\">private void initMap() {\r\n   PropertyHandler propertyHandler = null;\r\n   try {\r\n      propertyHandler = new PropertyHandler.Builder().setPropertiesFile(\".\/openmap.properties\").build();\r\n   } catch (IOException ex) {\r\n       Logger.getLogger(MapFrame.class.getName()).log(Level.SEVERE, null, ex);\r\n   }\r\n   ShapeLayer shapeLayer = new ShapeLayer();\r\n   if (propertyHandler != null) {\r\n      shapeLayer.setProperties(propertyHandler.getProperties());\r\n   }\r\n\r\n   \/\/ Add the political layer to the map\r\n   mapBean.add(shapeLayer);\r\n}\r\n<\/pre>\n<\/li>\n<\/ol>\n<h3>What about concurrency?<\/h3>\n<p>The only remaining hitch is that we load the map files in the EDT thread. If we need to load a big map this would delay the start of the application waiting for the big map to be loaded. We need to delegate this task to another thread.<\/p>\n<p>There are (at least) four ways to do this:<\/p>\n<ul>\n<li><code>javax.swing.SwingWorker<\/code><\/li>\n<li><code>com.bbn.openmap.util.SwingWorker<\/code><\/li>\n<li><code>java.awt.SecondaryLoop<\/code><\/a><\/li>\n<li><code>java.util.concurrent.CompletableFuture<\/code><\/li>\n<\/ul>\n<p>Let&#8217;s start looking at each one of them.<\/p>\n<h4>javax.swing.SwingWorker<\/h4>\n<p>The traditional way is to use a <code>SwingWorker <\/code>to do the dirty job (Listing 7). The generic class <code>SwingWorker <\/code>provides two parameterised types. The first parameterised type (<code>ShapeLayer<\/code>) is the return type for methods <code>doInBackground()<\/code> and <code>get()<\/code>. The object returned by <code>doInBackground()<\/code> is accessible by <code>get()<\/code> when the background task completes. The second parameterized type applies to periodically published values. This is useful when long\u2010running tasks publish partial results. Here, we use <code>Void<\/code>, since we don\u2019t publish partial results. The code inside <code>doInBackground()<\/code> is executed in a background thread. Here we read the properties using the <code>PropertyHandler <\/code>and create and return the <code>ShapeLayer<\/code>.<\/p>\n<p>To start the background thread, we invoke the <code>SwingWorker's execute()<\/code> method. This schedules the thread for execution and immediately returns. The <code>overridden done()<\/code> method is invoked in the EDT after the background task completes. This method is where you put code to update or refresh the <code>GUI. Method get()<\/code> blocks until the background task completes. However, if you call <code>get()<\/code> within method <code>done()<\/code>, no block occurs since the background task has finished. In this method we add the layer to the <code>mapBean<\/code>. However, since the <code>MapFrame <\/code>has already been rendered, it needs to be refreshed for the map layers to be rendered too. This is achieved by revalidating the <code>MapFrame<\/code>.<\/p>\n<p><em><strong>Listing 7: initMap() contents using a javax.swing.SwingWorker<\/strong><\/em><\/p>\n<pre class=\"brush:java\">private void initMap() {\r\n   SwingWorker&lt;ShapeLayer, Void&gt; worker = new SwingWorker&lt;ShapeLayer, Void&gt;() {\r\n\r\n     @Override\r\n     public ShapeLayer doInBackground() {\r\n       PropertyHandler propertyHandler = null;\r\n       try {\r\n           propertyHandler = new PropertyHandler.Builder().setPropertiesFile(\".\/openmap.properties\").build();\r\n       } catch (IOException ex) {\r\n          Logger.getLogger(MapFrame.class.getName()).log(Level.SEVERE, null, ex);\r\n       }\r\n       ShapeLayer shapeLayer = new ShapeLayer();\r\n       if (propertyHandler != null) {\r\n          shapeLayer.setProperties(propertyHandler.getProperties());\r\n       }\r\n       return shapeLayer;\r\n     }\r\n\r\n     @Override\r\n     protected void done() {\r\n        try {\r\n            if (!isCancelled()) {\r\n               \/\/ Add the political layer to the map\r\n               mapBean.add(get());\r\n               MapFrame.this.revalidate();\r\n            }\r\n        } catch (InterruptedException | ExecutionException ex) {\r\n          Logger.getLogger(MapFrame.class.getName()).log(Level.SEVERE, null, ex);\r\n        }\r\n     }\r\n   };\r\n   \/\/ invoke background thread\r\n   worker.execute();\r\n}\r\n<\/pre>\n<h4>com.bbn.openmap.util.SwingWorker<\/h4>\n<p>The second solution uses the <code>SwingWorker <\/code>provided by OpenMap (Listing 8). This is a simplified version of Java Swing&#8217;s SwingWorker. The parameterised type (<code>ShapeLayer<\/code>) is the return type of the construct() method. Here, we have refactored the creation of the <code>ShapeLayer<\/code> to its own method <code>getShapeLayer()<\/code> (Listing 9).<\/p>\n<p><em><strong>Listing 8: initMap() contents using a com.bbn.openmap.util.SwingWorker<\/strong><\/em><\/p>\n<pre class=\"brush:java\">private void initMap() {\r\n      com.bbn.openmap.util.SwingWorker&lt;ShapeLayer&gt; worker = new com.bbn.openmap.util.SwingWorker&lt;ShapeLayer&gt;() {\r\n\r\n         @Override\r\n         public ShapeLayer construct() {\r\n            return getShapeLayer();\r\n         }\r\n\r\n         @Override\r\n         public void finished() {\r\n            \/\/ Add the political layer to the map\r\n            mapBean.add(get());\r\n            MapFrame.this.revalidate();\r\n         }\r\n\r\n      };\r\n      \/\/ invoke background thread\r\n      worker.execute();\r\n}\r\n<\/pre>\n<p>To start the background thread, we invoke the SwingWorker&#8217;s <code>execute()<\/code> method. This schedules the thread for execution and immediately returns. The overridden <code>finished()<\/code> method is invoked in the EDT after the background task completes. This method is where you put code to update or refresh the GUI. <code>Method get()<\/code> blocks until the background task completes. However, if you call <code>get()<\/code> within method <code>finished()<\/code>, no block occurs since the background task has finished. In this method we add the layer to the <code>mapBean<\/code>. However, since the <code>MapFrame <\/code>has already been rendered, it needs to be refreshed for the map layers to be rendered too. This is achieved by revalidating the <code>MapFrame<\/code>.<\/p>\n<p>You can do this more obvious in a fast machine if you add a <code>Thread.sleep(10_000);<\/code> statement before the return statement in <code>construct()<\/code> method. You should see that the application&#8217;s window is <em>not<\/em> waiting for the <code>SwingWorker <\/code>to finish its work in order to be displayed.<\/p>\n<p><em><strong>Listing 9: getShapeLayer() refactored method<\/strong><\/em><\/p>\n<pre class=\"brush:java\">private ShapeLayer getShapeLayer() {\r\n    PropertyHandler propertyHandler = null;\r\n    try {\r\n        propertyHandler = new PropertyHandler.Builder().setPropertiesFile(\".\/openmap.properties\").build();\r\n    } catch (IOException ex) {\r\n        Logger.getLogger(MapFrame.class.getName()).log(Level.SEVERE, null, ex);\r\n    }\r\n    ShapeLayer shapeLayer = new ShapeLayer();\r\n    if (propertyHandler != null) {\r\n        shapeLayer.setProperties(propertyHandler.getProperties());\r\n    }\r\n\/\/    try {\r\n\/\/        Thread.sleep(10_000);\r\n\/\/    } catch (InterruptedException ex) {\r\n\/\/        Logger.getLogger(MapFrame.class.getName()).log(Level.SEVERE, null, ex);\r\n\/\/    }\r\n    return shapeLayer;\r\n}\r\n<\/pre>\n<h4><a href=\"http:\/\/docs.oracle.com\/javase\/7\/docs\/api\/java\/awt\/SecondaryLoop.html\">java.awt.SecondaryLoop<\/a><\/h4>\n<p>The third solution uses the SecondaryLoop (Listing 11). The interface provides two methods, <code>enter()<\/code> and <code>exit()<\/code>, which can be used to start and stop the event loop. Even though the loading of the properties and the creation of the shape layer are done in a different thread, the UI is not responsive and is waiting for the work thread to finish before it is rendered on the screen.<\/p>\n<p>From the JavaDoc: &#8220;When the <code>enter()<\/code> method is called, <strong><em>the current thread is blocked<\/em><\/strong> until the loop is terminated by the <code>exit()<\/code> method. Also, a new event loop is started on the event dispatch thread, which may or may not be the current thread. The loop can be terminated on any thread by calling its <code>exit()<\/code> method. [&#8230;] A typical use case of applying this interface is AWT and Swing modal dialogs. When a modal dialog is shown on the event dispatch thread, it enters a new secondary loop. Later, when the dialog is hidden or disposed, it exits the loop, and the thread continues its execution.&#8221; In other words, it does block the current thread so it is not a &#8216;replacement&#8217; of <code>SwingWorker <\/code>for all cases. There isn&#8217;t any <code>done()<\/code> callback method like in <code>SwingWorker <\/code>where you can call <code>get()<\/code> without blocking the current thread.<\/p>\n<p><em><strong>Listing 10: initMap() contents using a SecondaryLoop<\/strong><\/em><\/p>\n<pre class=\"brush:java\">private void initMap() {\r\n   final ShapeLayer shapeLayer = new ShapeLayer();\r\n   final SecondaryLoop loop = Toolkit.getDefaultToolkit().getSystemEventQueue().createSecondaryLoop();\r\n   Thread work = new Thread() {\r\n\r\n       @Override\r\n       public void run() {\r\n         PropertyHandler propertyHandler = null;\r\n         try {\r\n             propertyHandler = new PropertyHandler.Builder().setPropertiesFile(\".\/openmap.properties\").build();\r\n         } catch (IOException ex) {\r\n            Logger.getLogger(MapFrame.class.getName()).log(Level.SEVERE, null, ex);\r\n         }\r\n\r\n         if (propertyHandler != null) {\r\n            shapeLayer.setProperties(propertyHandler.getProperties());\r\n         }\r\n         loop.exit();\r\n      }\r\n\r\n   };\r\n\r\n   \/\/ We start the thread to do the real work  \r\n   work.start();\r\n\r\n   \/\/ Blocks until loop.exit() is called  \r\n   loop.enter();\r\n\r\n   \/\/ Add the political layer to the map\r\n   mapBean.add(shapeLayer);\r\n}\r\n<\/pre>\n<h4>java.util.concurrent.CompletableFuture<\/h4>\n<p>Java 8 provides a new class, <code>CompletableFuture<\/code>. <code>CompletableFuture&lt;T&gt;<\/code> extends <code>Future&lt;T&gt;<\/code> by providing functional, monadic operations and promoting asynchronous, event-driven programming model, as opposed to blocking in older Java.<\/p>\n<p>You need to have JDK 8 or later to be able to use it. If you don&#8217;t, right-click on the <em>OpenMap<\/em> project and select <strong>Properties<\/strong>. Select the category <strong>Libraries<\/strong> and select a <em>Java 8<\/em> Java Platform (you may need to add a new Java 8 platform by clicking on <strong>Manage Platforms<\/strong> button and navigating to the folder where you downloaded and installed JDK 8). Then, select the <strong>Sources<\/strong> category and change the <em>Source\/Binary Format<\/em> to <strong>JDK 8<\/strong>.<\/p>\n<p>Typically Futures represent piece of code running by other thread, but they are not asynchronous, i.e. you can not tell them to execute a task asynchrously and return back sometime in the future with the result. In this case you can simply create a CompletableFuture, return it to your client and whenever you think your results are available, simply <code>complete()<\/code> the future and unlock all clients waiting on that future. There is of course a blocking <code>get()<\/code> method like in the case of SwingWorker.<\/p>\n<p>CompletableFuture provides <em>async<\/em> methods which execute their task in another thread than the previous task as well as <em>non-async<\/em> methods which execute their task in the same thread as the previous task. In <em>async<\/em> methods, the task is submitted to a fork-join thread pool and when it finishes, the result is passed to the next task. When the next task finishes, its result is sent further and so on. It&#8217;s quite neat and simple.<\/p>\n<p><em><strong>Listing 11: initMap() contents using a CompletableFuture<\/strong><\/em><\/p>\n<pre class=\"brush:java\">private void initMap() {\r\n   CompletableFuture.supplyAsync(() -&gt; getShapeLayer()).thenAcceptAsync(\r\n      shapeLayer -&gt; {\r\n          \/\/ Add the political layer to the map\r\n          mapBean.add(shapeLayer);\r\n          MapFrame.this.revalidate();\r\n      });\r\n}\r\n<\/pre>\n<p>The modified initMap() is shown in Listing 11. You can supply a new task to the global, general purpose <code>ForkJoinPool.commonPool()<\/code> introduced in JDK 8 by calling <code>supplyAsync()<\/code> and passing a <code>Supplier<\/code> (<code>() -&gt; getShapeLayer()<\/code>). There is also an overriden <code>supplyAsync()<\/code> method which accepts an Executor if you don&#8217;t want to use the common thread pool. A <code>Supplier&lt;R&gt;<\/code> is a new interface introduced in Java 8 which accepts no parameters and returns a value of type <code>R<\/code> (a <code>ShapeLayer<\/code> in our case).<\/p>\n<p>You can apply further processings by using <code>thenApply()<\/code> or<code> thenApplyAsync()<\/code> methods (which accept a <code>Function&lt;T, R&gt;<\/code>) but this is not needed for our example.<\/p>\n<p>You can get the result back asynchronously by using the <em>non-blocking<\/em> <code>thenAccept()<\/code> or <code>thenAcceptAsync()<\/code> methods, which accepts a <code>Consumer&lt;T&gt;<\/code>. They allow you to consume future value when it&#8217;s ready. A <code>Consumer&lt;T&gt;<\/code> is the oposite to a <code>Supplier&lt;R&gt;;<\/code> it accepts a parameter of type <code>T<\/code> and returns <code>void<\/code>.<\/p>\n<p>See how elegant this last solution is.<\/p>\n<h2>Conclusion<\/h2>\n<p>We went a long way in this first tutorial of OpenMap. We learned how to create a <code>MapFrame <\/code>in NetBeans IDE which is a Swing <code>JFrame <\/code>and saw how to use the IDE to add <em>OpenMap<\/em> JavaBeans to the Palette and then drag a <code>MapBean <\/code>onto the <code>MapFrame<\/code>. We learned how to add layers to the <code>MapBean <\/code>in order to display <code>.shp<\/code> map files. Layers are configured via property files. We saw how to use the <code>PropertyHandler <\/code>to read our properties. We also saw four ways of how to load our map files from a different thread in order to keep our <code>MapFrame <\/code>responsive even when the map files take too long to load.<\/p>\n<p>In the next tutorial we shall go into more depth into the internals of <em>OpenMap<\/em> learning about <code>MapHandler<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction This series of tutorials will show you how to build Java applications using the OpenMap GIS Java Swing library. OpenMap&#8217;s Developer guide is a very useful document that describes OpenMap&#8217;s architecture but it doesn&#8217;t explain how to start and build up an application step-by-step. The examples that come together with the source code are &hellip;<\/p>\n","protected":false},"author":734,"featured_media":148,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[88,1221,262],"class_list":["post-46705","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-desktop-java","tag-concurrency","tag-openmap","tag-swing"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>OpenMap Tutorial - Part 1 - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"Introduction This series of tutorials will show you how to build Java applications using the OpenMap GIS Java Swing library. OpenMap&#039;s Developer guide is\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"OpenMap Tutorial - Part 1 - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"Introduction This series of tutorials will show you how to build Java applications using the OpenMap GIS Java Swing library. OpenMap&#039;s Developer guide is\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2015-10-12T07:00:18+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/java-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Ioannis Kostaras\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Ioannis Kostaras\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"17 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/10\\\/openmap-tutorial-part-1.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/10\\\/openmap-tutorial-part-1.html\"},\"author\":{\"name\":\"Ioannis Kostaras\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/8777c97598d66c2d54677864d04c279a\"},\"headline\":\"OpenMap Tutorial &#8211; Part 1\",\"datePublished\":\"2015-10-12T07:00:18+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/10\\\/openmap-tutorial-part-1.html\"},\"wordCount\":2565,\"commentCount\":6,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/10\\\/openmap-tutorial-part-1.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/java-logo.jpg\",\"keywords\":[\"Concurrency\",\"OpenMap\",\"Swing\"],\"articleSection\":[\"Desktop Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/10\\\/openmap-tutorial-part-1.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/10\\\/openmap-tutorial-part-1.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/10\\\/openmap-tutorial-part-1.html\",\"name\":\"OpenMap Tutorial - Part 1 - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/10\\\/openmap-tutorial-part-1.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/10\\\/openmap-tutorial-part-1.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/java-logo.jpg\",\"datePublished\":\"2015-10-12T07:00:18+00:00\",\"description\":\"Introduction This series of tutorials will show you how to build Java applications using the OpenMap GIS Java Swing library. OpenMap's Developer guide is\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/10\\\/openmap-tutorial-part-1.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/10\\\/openmap-tutorial-part-1.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/10\\\/openmap-tutorial-part-1.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/java-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/java-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2015\\\/10\\\/openmap-tutorial-part-1.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Desktop Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/desktop-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"OpenMap Tutorial &#8211; Part 1\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/8777c97598d66c2d54677864d04c279a\",\"name\":\"Ioannis Kostaras\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/6f7f24d8834f6097783371ff0cbf8c4d363006a95cd8ca67e47c2c1b8efeb051?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/6f7f24d8834f6097783371ff0cbf8c4d363006a95cd8ca67e47c2c1b8efeb051?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/6f7f24d8834f6097783371ff0cbf8c4d363006a95cd8ca67e47c2c1b8efeb051?s=96&d=mm&r=g\",\"caption\":\"Ioannis Kostaras\"},\"description\":\"Software architect awarded the 2012 Duke's Choice Community Choice Award and co-organizing the hottest Java conference on earth, JCrete.\",\"sameAs\":[\"http:\\\/\\\/www.jcrete.org\\\/\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/john-kostaras\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"OpenMap Tutorial - Part 1 - Java Code Geeks","description":"Introduction This series of tutorials will show you how to build Java applications using the OpenMap GIS Java Swing library. OpenMap's Developer guide is","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html","og_locale":"en_US","og_type":"article","og_title":"OpenMap Tutorial - Part 1 - Java Code Geeks","og_description":"Introduction This series of tutorials will show you how to build Java applications using the OpenMap GIS Java Swing library. OpenMap's Developer guide is","og_url":"https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2015-10-12T07:00:18+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/java-logo.jpg","type":"image\/jpeg"}],"author":"Ioannis Kostaras","twitter_card":"summary_large_image","twitter_creator":"@javacodegeeks","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Ioannis Kostaras","Est. reading time":"17 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html"},"author":{"name":"Ioannis Kostaras","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/8777c97598d66c2d54677864d04c279a"},"headline":"OpenMap Tutorial &#8211; Part 1","datePublished":"2015-10-12T07:00:18+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html"},"wordCount":2565,"commentCount":6,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/java-logo.jpg","keywords":["Concurrency","OpenMap","Swing"],"articleSection":["Desktop Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html","url":"https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html","name":"OpenMap Tutorial - Part 1 - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/java-logo.jpg","datePublished":"2015-10-12T07:00:18+00:00","description":"Introduction This series of tutorials will show you how to build Java applications using the OpenMap GIS Java Swing library. OpenMap's Developer guide is","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/java-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/java-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2015\/10\/openmap-tutorial-part-1.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Desktop Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/desktop-java"},{"@type":"ListItem","position":4,"name":"OpenMap Tutorial &#8211; Part 1"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/8777c97598d66c2d54677864d04c279a","name":"Ioannis Kostaras","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/6f7f24d8834f6097783371ff0cbf8c4d363006a95cd8ca67e47c2c1b8efeb051?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/6f7f24d8834f6097783371ff0cbf8c4d363006a95cd8ca67e47c2c1b8efeb051?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/6f7f24d8834f6097783371ff0cbf8c4d363006a95cd8ca67e47c2c1b8efeb051?s=96&d=mm&r=g","caption":"Ioannis Kostaras"},"description":"Software architect awarded the 2012 Duke's Choice Community Choice Award and co-organizing the hottest Java conference on earth, JCrete.","sameAs":["http:\/\/www.jcrete.org\/"],"url":"https:\/\/www.javacodegeeks.com\/author\/john-kostaras"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/46705","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/734"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=46705"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/46705\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/148"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=46705"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=46705"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=46705"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}