{"action":"created","comment":{"url":"https://api.github.com/repos/geotools/geotools/pulls/comments/23105544","id":23105544,"diff_hunk":"@@ -0,0 +1,174 @@\n+/* GeoTools - The Open Source Java GIS Toolkit\n+ * http://geotools.org\n+ *\n+ * (C) 2010-2014, Open Source Geospatial Foundation (OSGeo)\n+ *\n+ * This file is hereby placed into the Public Domain. This means anyone is\n+ * free to do whatever they wish with this file. Use it well and enjoy!\n+ */\n+package org.geotools.data.csv;\n+\n+import java.io.File;\n+import java.io.FileWriter;\n+import java.io.IOException;\n+import java.nio.file.Files;\n+import java.nio.file.StandardCopyOption;\n+import java.util.NoSuchElementException;\n+\n+import org.geotools.data.DataUtilities;\n+import org.geotools.data.FeatureWriter;\n+import org.geotools.data.Query;\n+import org.geotools.data.csv.parse.CSVIterator;\n+import org.geotools.data.csv.parse.CSVStrategy;\n+import org.geotools.feature.simple.SimpleFeatureBuilder;\n+import org.opengis.feature.simple.SimpleFeature;\n+import org.opengis.feature.simple.SimpleFeatureType;\n+\n+import com.csvreader.CsvWriter;\n+\n+/**\n+ * Iterator supporting writing of feature content.\n+ *\n+ * @author Jody Garnett (Boundless)\n+ * @author Lee Breisacher\n+ */\n+public class CSVFeatureWriter implements FeatureWriter<SimpleFeatureType, SimpleFeature> {\n+    private SimpleFeatureType featureType;\n+    private CSVStrategy csvStrategy;\n+    private CSVFileState csvFileState;\n+    \n+    /** Temporary file used to stage output */\n+    private File temp;\n+    \n+    /** iterator handling reading of original file(?) */\n+    private CSVIterator iterator;\n+    \n+    /** CsvWriter used for temp file output */\n+    private CsvWriter csvWriter;\n+    \n+    /** Flag indicating we have reached the end of the file */\n+    private boolean appending = false;\n+    \n+    /** Row count used to generate FeatureId when appending */\n+    int nextRow = 0;\n+    \n+    /** Current feature available for modification. May be null if feature removed */\n+    private SimpleFeature currentFeature;\n+\n+    public CSVFeatureWriter(CSVFileState csvFileState, CSVStrategy csvStrategy)\n+    \t\tthrows IOException {\n+        this(csvFileState, csvStrategy, Query.ALL);\n+    }\n+    \n+    public CSVFeatureWriter(CSVFileState csvFileState, CSVStrategy csvStrategy, Query query)\n+    \t\tthrows IOException {\n+    \tthis.csvFileState = csvFileState;\n+    \tFile file = csvFileState.getFile();\n+    \tFile directory = file.getParentFile();\n+    \tString typeName = query.getTypeName();\n+    \tthis.temp = File.createTempFile(typeName + System.currentTimeMillis(), \"csv\", directory);\n+    \tthis.featureType = csvStrategy.getFeatureType();\n+    \tthis.iterator = csvStrategy.iterator();\n+    \tthis.csvStrategy = csvStrategy;\n+    \tthis.csvWriter = new CsvWriter(new FileWriter(this.temp), ',');\n+    \tthis.csvWriter.writeRecord(this.csvFileState.getCSVHeaders());\n+    }\n+    \n+    // featureType start\n+    @Override\n+    public SimpleFeatureType getFeatureType() {\n+        return this.featureType;\n+    }\n+    // featureType end\n+\n+    // hasNext start\n+    @Override\n+    public boolean hasNext() throws IOException {\n+        if( csvWriter == null ){\n+            throw new IOException(\"Writer has been closed\");\n+        }\n+        if (this.appending) {\n+            return false; // reader has no more contents\n+        }\n+        return iterator.hasNext();\n+    }\n+    // hasNext end\n+    \n+    // next start\n+    @Override\n+    public SimpleFeature next() throws IOException, IllegalArgumentException,\n+            NoSuchElementException {\n+        if(csvWriter == null){\n+            throw new IOException(\"Writer has been closed\");\n+        }\n+        if (this.currentFeature != null) {\n+            this.write(); // the previous one was not written, so do it now.\n+        }\n+        try {\n+            if(!appending){\n+                if(iterator.hasNext()){\n+                    this.currentFeature = iterator.next();\n+                    return this.currentFeature;\n+                }\n+                else {\n+                    this.appending = true;\n+                }\n+            }\n+            String fid = featureType.getTypeName()+\".\"+nextRow;\n+            Object values[] = DataUtilities.defaultValues( featureType );\n+            \n+            this.currentFeature = SimpleFeatureBuilder.build( featureType, values, fid );\n+            return this.currentFeature;\n+        }\n+        catch (IllegalArgumentException invalid ){\n+            throw new IOException(\"Unable to create feature:\"+invalid.getMessage(),invalid);\n+        }\n+    }\n+    // next end\n+    \n+    // remove start\n+    /**\n+     * Mark our {@link #currentFeature} feature as null, it will be skipped when written effectively removing it.\n+     */\n+    public void remove() throws IOException {\n+        this.currentFeature = null; // just mark it done which means it will not get written out.\n+    }\n+    // remove end\n+    \n+    // write start\n+    public void write() throws IOException {\n+        if (this.currentFeature == null) {\n+            return; // current feature has been deleted\n+        }\n+        this.csvWriter.writeRecord(this.csvStrategy.encode(this.currentFeature));\n+        nextRow++;\n+        this.currentFeature = null; // indicate that it has been written\n+    }\n+    // write end\n+    \n+    // close start\n+    @Override\n+    public void close() throws IOException {\n+        if( csvWriter == null ){\n+            throw new IOException(\"Writer alread closed\");\n+        }\n+        if (this.currentFeature != null) {\n+            this.write(); // the previous one was not written, so do it now.\n+        }\n+        // Step 1: Write out remaining contents (if applicable)\n+        while (hasNext()) {\n+            next();\n+            write();\n+        }\n+        csvWriter.close();","path":"modules/unsupported/csv/src/main/java/org/geotools/data/csv/CSVFeatureWriter.java","position":163,"original_position":163,"commit_id":"abaa75af9dba507ec24ec6c912e5b495518a1292","original_commit_id":"abaa75af9dba507ec24ec6c912e5b495518a1292","user":{"login":"jodygarnett","id":629681,"avatar_url":"https://avatars.githubusercontent.com/u/629681?v=3","gravatar_id":"","url":"https://api.github.com/users/jodygarnett","html_url":"https://github.com/jodygarnett","followers_url":"https://api.github.com/users/jodygarnett/followers","following_url":"https://api.github.com/users/jodygarnett/following{/other_user}","gists_url":"https://api.github.com/users/jodygarnett/gists{/gist_id}","starred_url":"https://api.github.com/users/jodygarnett/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jodygarnett/subscriptions","organizations_url":"https://api.github.com/users/jodygarnett/orgs","repos_url":"https://api.github.com/users/jodygarnett/repos","events_url":"https://api.github.com/users/jodygarnett/events{/privacy}","received_events_url":"https://api.github.com/users/jodygarnett/received_events","type":"User","site_admin":false},"body":"I sure hope this closes the FIleWriter we passed into it (during the constructor)","created_at":"2015-01-16T20:03:26Z","updated_at":"2015-01-16T20:03:26Z","html_url":"https://github.com/geotools/geotools/pull/692#discussion_r23105544","pull_request_url":"https://api.github.com/repos/geotools/geotools/pulls/692","_links":{"self":{"href":"https://api.github.com/repos/geotools/geotools/pulls/comments/23105544"},"html":{"href":"https://github.com/geotools/geotools/pull/692#discussion_r23105544"},"pull_request":{"href":"https://api.github.com/repos/geotools/geotools/pulls/692"}}},"pull_request":{"url":"https://api.github.com/repos/geotools/geotools/pulls/692","id":27481372,"html_url":"https://github.com/geotools/geotools/pull/692","diff_url":"https://github.com/geotools/geotools/pull/692.diff","patch_url":"https://github.com/geotools/geotools/pull/692.patch","issue_url":"https://api.github.com/repos/geotools/geotools/issues/692","number":692,"state":"open","locked":false,"title":"Updating CSVDataStore for write functionality","user":{"login":"travislbrundage","id":8084860,"avatar_url":"https://avatars.githubusercontent.com/u/8084860?v=3","gravatar_id":"","url":"https://api.github.com/users/travislbrundage","html_url":"https://github.com/travislbrundage","followers_url":"https://api.github.com/users/travislbrundage/followers","following_url":"https://api.github.com/users/travislbrundage/following{/other_user}","gists_url":"https://api.github.com/users/travislbrundage/gists{/gist_id}","starred_url":"https://api.github.com/users/travislbrundage/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/travislbrundage/subscriptions","organizations_url":"https://api.github.com/users/travislbrundage/orgs","repos_url":"https://api.github.com/users/travislbrundage/repos","events_url":"https://api.github.com/users/travislbrundage/events{/privacy}","received_events_url":"https://api.github.com/users/travislbrundage/received_events","type":"User","site_admin":false},"body":"This is an update of the CSVDataStore to give it read/write functionality.\r\n\r\nSome design issues to note:\r\nI merged the original CSVStrategy interface and AbstractCSVStrategy into one. They now reside in the abstract class, CSVStrategy. I did not see much sense in having both in this case.\r\nI have opted to migrate all the methods from the CSVStrategySupport class into CSVStrategy. They are somewhat odd helper methods that could use some refactoring in the future, but for now I have put them there so that individual strategies can choose to override them and possibly make them more appropriate.\r\nA few other smaller changes include making the lat/lon to x/y mapping consistent and storing the Point geometry where the LAT column resided.\r\n\r\nFinally, for testing, I have included both the old CSVWriteTest to test basic file writing, and I have created a new CSVWriteStrategyTest which tests each strategy's implementation.","created_at":"2015-01-16T03:04:13Z","updated_at":"2015-01-16T20:03:26Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a41ff45689bf59bce3856fccaa69c950981cb4b0","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/geotools/geotools/pulls/692/commits","review_comments_url":"https://api.github.com/repos/geotools/geotools/pulls/692/comments","review_comment_url":"https://api.github.com/repos/geotools/geotools/pulls/comments/{number}","comments_url":"https://api.github.com/repos/geotools/geotools/issues/692/comments","statuses_url":"https://api.github.com/repos/geotools/geotools/statuses/abaa75af9dba507ec24ec6c912e5b495518a1292","head":{"label":"travislbrundage:csvdatastore-write-strategy","ref":"csvdatastore-write-strategy","sha":"abaa75af9dba507ec24ec6c912e5b495518a1292","user":{"login":"travislbrundage","id":8084860,"avatar_url":"https://avatars.githubusercontent.com/u/8084860?v=3","gravatar_id":"","url":"https://api.github.com/users/travislbrundage","html_url":"https://github.com/travislbrundage","followers_url":"https://api.github.com/users/travislbrundage/followers","following_url":"https://api.github.com/users/travislbrundage/following{/other_user}","gists_url":"https://api.github.com/users/travislbrundage/gists{/gist_id}","starred_url":"https://api.github.com/users/travislbrundage/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/travislbrundage/subscriptions","organizations_url":"https://api.github.com/users/travislbrundage/orgs","repos_url":"https://api.github.com/users/travislbrundage/repos","events_url":"https://api.github.com/users/travislbrundage/events{/privacy}","received_events_url":"https://api.github.com/users/travislbrundage/received_events","type":"User","site_admin":false},"repo":{"id":28113982,"name":"geotools","full_name":"travislbrundage/geotools","owner":{"login":"travislbrundage","id":8084860,"avatar_url":"https://avatars.githubusercontent.com/u/8084860?v=3","gravatar_id":"","url":"https://api.github.com/users/travislbrundage","html_url":"https://github.com/travislbrundage","followers_url":"https://api.github.com/users/travislbrundage/followers","following_url":"https://api.github.com/users/travislbrundage/following{/other_user}","gists_url":"https://api.github.com/users/travislbrundage/gists{/gist_id}","starred_url":"https://api.github.com/users/travislbrundage/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/travislbrundage/subscriptions","organizations_url":"https://api.github.com/users/travislbrundage/orgs","repos_url":"https://api.github.com/users/travislbrundage/repos","events_url":"https://api.github.com/users/travislbrundage/events{/privacy}","received_events_url":"https://api.github.com/users/travislbrundage/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/travislbrundage/geotools","description":"Official GeoTools repository","fork":true,"url":"https://api.github.com/repos/travislbrundage/geotools","forks_url":"https://api.github.com/repos/travislbrundage/geotools/forks","keys_url":"https://api.github.com/repos/travislbrundage/geotools/keys{/key_id}","collaborators_url":"https://api.github.com/repos/travislbrundage/geotools/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/travislbrundage/geotools/teams","hooks_url":"https://api.github.com/repos/travislbrundage/geotools/hooks","issue_events_url":"https://api.github.com/repos/travislbrundage/geotools/issues/events{/number}","events_url":"https://api.github.com/repos/travislbrundage/geotools/events","assignees_url":"https://api.github.com/repos/travislbrundage/geotools/assignees{/user}","branches_url":"https://api.github.com/repos/travislbrundage/geotools/branches{/branch}","tags_url":"https://api.github.com/repos/travislbrundage/geotools/tags","blobs_url":"https://api.github.com/repos/travislbrundage/geotools/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/travislbrundage/geotools/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/travislbrundage/geotools/git/refs{/sha}","trees_url":"https://api.github.com/repos/travislbrundage/geotools/git/trees{/sha}","statuses_url":"https://api.github.com/repos/travislbrundage/geotools/statuses/{sha}","languages_url":"https://api.github.com/repos/travislbrundage/geotools/languages","stargazers_url":"https://api.github.com/repos/travislbrundage/geotools/stargazers","contributors_url":"https://api.github.com/repos/travislbrundage/geotools/contributors","subscribers_url":"https://api.github.com/repos/travislbrundage/geotools/subscribers","subscription_url":"https://api.github.com/repos/travislbrundage/geotools/subscription","commits_url":"https://api.github.com/repos/travislbrundage/geotools/commits{/sha}","git_commits_url":"https://api.github.com/repos/travislbrundage/geotools/git/commits{/sha}","comments_url":"https://api.github.com/repos/travislbrundage/geotools/comments{/number}","issue_comment_url":"https://api.github.com/repos/travislbrundage/geotools/issues/comments/{number}","contents_url":"https://api.github.com/repos/travislbrundage/geotools/contents/{+path}","compare_url":"https://api.github.com/repos/travislbrundage/geotools/compare/{base}...{head}","merges_url":"https://api.github.com/repos/travislbrundage/geotools/merges","archive_url":"https://api.github.com/repos/travislbrundage/geotools/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/travislbrundage/geotools/downloads","issues_url":"https://api.github.com/repos/travislbrundage/geotools/issues{/number}","pulls_url":"https://api.github.com/repos/travislbrundage/geotools/pulls{/number}","milestones_url":"https://api.github.com/repos/travislbrundage/geotools/milestones{/number}","notifications_url":"https://api.github.com/repos/travislbrundage/geotools/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/travislbrundage/geotools/labels{/name}","releases_url":"https://api.github.com/repos/travislbrundage/geotools/releases{/id}","created_at":"2014-12-17T00:46:08Z","updated_at":"2014-12-17T00:46:43Z","pushed_at":"2015-01-16T03:03:38Z","git_url":"git://github.com/travislbrundage/geotools.git","ssh_url":"git@github.com:travislbrundage/geotools.git","clone_url":"https://github.com/travislbrundage/geotools.git","svn_url":"https://github.com/travislbrundage/geotools","homepage":"http://geotools.org","size":104196,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"geotools:master","ref":"master","sha":"32330d3ea6868492be7c6b0d57a8311ab4524f7c","user":{"login":"geotools","id":1187031,"avatar_url":"https://avatars.githubusercontent.com/u/1187031?v=3","gravatar_id":"","url":"https://api.github.com/users/geotools","html_url":"https://github.com/geotools","followers_url":"https://api.github.com/users/geotools/followers","following_url":"https://api.github.com/users/geotools/following{/other_user}","gists_url":"https://api.github.com/users/geotools/gists{/gist_id}","starred_url":"https://api.github.com/users/geotools/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/geotools/subscriptions","organizations_url":"https://api.github.com/users/geotools/orgs","repos_url":"https://api.github.com/users/geotools/repos","events_url":"https://api.github.com/users/geotools/events{/privacy}","received_events_url":"https://api.github.com/users/geotools/received_events","type":"Organization","site_admin":false},"repo":{"id":2752522,"name":"geotools","full_name":"geotools/geotools","owner":{"login":"geotools","id":1187031,"avatar_url":"https://avatars.githubusercontent.com/u/1187031?v=3","gravatar_id":"","url":"https://api.github.com/users/geotools","html_url":"https://github.com/geotools","followers_url":"https://api.github.com/users/geotools/followers","following_url":"https://api.github.com/users/geotools/following{/other_user}","gists_url":"https://api.github.com/users/geotools/gists{/gist_id}","starred_url":"https://api.github.com/users/geotools/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/geotools/subscriptions","organizations_url":"https://api.github.com/users/geotools/orgs","repos_url":"https://api.github.com/users/geotools/repos","events_url":"https://api.github.com/users/geotools/events{/privacy}","received_events_url":"https://api.github.com/users/geotools/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/geotools/geotools","description":"Official GeoTools repository","fork":false,"url":"https://api.github.com/repos/geotools/geotools","forks_url":"https://api.github.com/repos/geotools/geotools/forks","keys_url":"https://api.github.com/repos/geotools/geotools/keys{/key_id}","collaborators_url":"https://api.github.com/repos/geotools/geotools/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/geotools/geotools/teams","hooks_url":"https://api.github.com/repos/geotools/geotools/hooks","issue_events_url":"https://api.github.com/repos/geotools/geotools/issues/events{/number}","events_url":"https://api.github.com/repos/geotools/geotools/events","assignees_url":"https://api.github.com/repos/geotools/geotools/assignees{/user}","branches_url":"https://api.github.com/repos/geotools/geotools/branches{/branch}","tags_url":"https://api.github.com/repos/geotools/geotools/tags","blobs_url":"https://api.github.com/repos/geotools/geotools/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/geotools/geotools/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/geotools/geotools/git/refs{/sha}","trees_url":"https://api.github.com/repos/geotools/geotools/git/trees{/sha}","statuses_url":"https://api.github.com/repos/geotools/geotools/statuses/{sha}","languages_url":"https://api.github.com/repos/geotools/geotools/languages","stargazers_url":"https://api.github.com/repos/geotools/geotools/stargazers","contributors_url":"https://api.github.com/repos/geotools/geotools/contributors","subscribers_url":"https://api.github.com/repos/geotools/geotools/subscribers","subscription_url":"https://api.github.com/repos/geotools/geotools/subscription","commits_url":"https://api.github.com/repos/geotools/geotools/commits{/sha}","git_commits_url":"https://api.github.com/repos/geotools/geotools/git/commits{/sha}","comments_url":"https://api.github.com/repos/geotools/geotools/comments{/number}","issue_comment_url":"https://api.github.com/repos/geotools/geotools/issues/comments/{number}","contents_url":"https://api.github.com/repos/geotools/geotools/contents/{+path}","compare_url":"https://api.github.com/repos/geotools/geotools/compare/{base}...{head}","merges_url":"https://api.github.com/repos/geotools/geotools/merges","archive_url":"https://api.github.com/repos/geotools/geotools/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/geotools/geotools/downloads","issues_url":"https://api.github.com/repos/geotools/geotools/issues{/number}","pulls_url":"https://api.github.com/repos/geotools/geotools/pulls{/number}","milestones_url":"https://api.github.com/repos/geotools/geotools/milestones{/number}","notifications_url":"https://api.github.com/repos/geotools/geotools/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/geotools/geotools/labels{/name}","releases_url":"https://api.github.com/repos/geotools/geotools/releases{/id}","created_at":"2011-11-10T23:22:12Z","updated_at":"2015-01-16T18:25:50Z","pushed_at":"2015-01-16T18:25:50Z","git_url":"git://github.com/geotools/geotools.git","ssh_url":"git@github.com:geotools/geotools.git","clone_url":"https://github.com/geotools/geotools.git","svn_url":"https://github.com/geotools/geotools","homepage":"http://geotools.org","size":211144,"stargazers_count":170,"watchers_count":170,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":252,"mirror_url":null,"open_issues_count":11,"forks":252,"open_issues":11,"watchers":170,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/geotools/geotools/pulls/692"},"html":{"href":"https://github.com/geotools/geotools/pull/692"},"issue":{"href":"https://api.github.com/repos/geotools/geotools/issues/692"},"comments":{"href":"https://api.github.com/repos/geotools/geotools/issues/692/comments"},"review_comments":{"href":"https://api.github.com/repos/geotools/geotools/pulls/692/comments"},"review_comment":{"href":"https://api.github.com/repos/geotools/geotools/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/geotools/geotools/pulls/692/commits"},"statuses":{"href":"https://api.github.com/repos/geotools/geotools/statuses/abaa75af9dba507ec24ec6c912e5b495518a1292"}}}}