diff --git a/README.md b/README.md index 07bb588..a826bdc 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ and ``` # Example: Using the Java Client - +## Up to 2.0.0 ```java package com.redislabs.redisgraph; @@ -80,3 +80,60 @@ public class RedisGraphExample { } ``` +## From 2.0.0 + +```java +package com.redislabs.redisgraph; + +import com.redislabs.redisgraph.graph_entities.Edge; +import com.redislabs.redisgraph.graph_entities.Node; +import com.redislabs.redisgraph.impl.api.RedisGraph; + +import java.util.List; + +public class RedisGraphExample { + public static void main(String[] args) { + // general context api. Not bound to graph key or connection + RedisGraph graph = new RedisGraph(); + + // send queries to a specific graph called "social" + graph.query("social","CREATE (:person{name:'roi',age:32})"); + graph.query("social","CREATE (:person{name:%s,age:%d})", "amit", 30); + graph.query("social","MATCH (a:person), (b:person) WHERE (a.name = 'roi' AND b.name='amit') CREATE (a)-[:knows]->(b)"); + + ResultSet resultSet = graph.query("social", "MATCH (a:person)-[r:knows]->(b:person) RETURN a, r, b"); + while(resultSet.hasNext()) { + Record record = resultSet.next(); + // get values + Node a = record.getValue("a"); + Edge r = record.getValue("r"); + + //print record + System.out.println(record.toString()); + } + + // delete graph + graph.deleteGraph("social"); + + // get connection context - closable object + try(RedisGraphContext context = graph.getContext()) { + context.query("contextSocial","CREATE (:person{name:'roi',age:32})"); + context.query("contextSocial","CREATE (:person{name:%s,age:%d})", "amit", 30); + context.query("contextSocial", "MATCH (a:person), (b:person) WHERE (a.name = 'roi' AND b.name='amit') CREATE (a)-[:knows]->(b)"); + // WATCH/MULTI/EXEC + context.watch("contextSocial"); + RedisGraphTransaction t = context.multi(); + t.query("contextSocial", "MATCH (a:person)-[r:knows]->(b:person) RETURN a, r, b"); + // support for Redis/Jedis native commands in transaction + t.set("x", "1"); + t.get("x"); + // get multi/exec results + List execResults = t.exec(); + System.out.println(execResults.toString()); + + context.deleteGraph("contextSocial"); + } + } +} + +``` diff --git a/src/main/java/com/redislabs/redisgraph/RedisGraph.java b/src/main/java/com/redislabs/redisgraph/RedisGraph.java index 90432bd..25c4718 100644 --- a/src/main/java/com/redislabs/redisgraph/RedisGraph.java +++ b/src/main/java/com/redislabs/redisgraph/RedisGraph.java @@ -49,4 +49,6 @@ public interface RedisGraph extends Closeable { */ String deleteGraph(String graphId); + @Override + void close(); } diff --git a/src/main/java/com/redislabs/redisgraph/RedisGraphContexted.java b/src/main/java/com/redislabs/redisgraph/RedisGraphContext.java similarity index 92% rename from src/main/java/com/redislabs/redisgraph/RedisGraphContexted.java rename to src/main/java/com/redislabs/redisgraph/RedisGraphContext.java index 5ef1037..db2a5e8 100644 --- a/src/main/java/com/redislabs/redisgraph/RedisGraphContexted.java +++ b/src/main/java/com/redislabs/redisgraph/RedisGraphContext.java @@ -2,7 +2,7 @@ import redis.clients.jedis.Jedis; -public interface RedisGraphContexted extends RedisGraph { +public interface RedisGraphContext extends RedisGraph { /** diff --git a/src/main/java/com/redislabs/redisgraph/RedisGraphGeneralContext.java b/src/main/java/com/redislabs/redisgraph/RedisGraphContextGenerator.java similarity index 56% rename from src/main/java/com/redislabs/redisgraph/RedisGraphGeneralContext.java rename to src/main/java/com/redislabs/redisgraph/RedisGraphContextGenerator.java index cdf218a..fe3718f 100644 --- a/src/main/java/com/redislabs/redisgraph/RedisGraphGeneralContext.java +++ b/src/main/java/com/redislabs/redisgraph/RedisGraphContextGenerator.java @@ -1,11 +1,11 @@ package com.redislabs.redisgraph; -public interface RedisGraphGeneralContext extends RedisGraph { +public interface RedisGraphContextGenerator extends RedisGraph { /** * Generate a connection bounded api * @return a connection bounded api */ - RedisGraphContexted getContextedAPI(); + RedisGraphContext getContext(); } diff --git a/src/main/java/com/redislabs/redisgraph/impl/api/ContextedRedisGraph.java b/src/main/java/com/redislabs/redisgraph/impl/api/ContextedRedisGraph.java index b2fe9f6..b846925 100644 --- a/src/main/java/com/redislabs/redisgraph/impl/api/ContextedRedisGraph.java +++ b/src/main/java/com/redislabs/redisgraph/impl/api/ContextedRedisGraph.java @@ -1,6 +1,6 @@ package com.redislabs.redisgraph.impl.api; -import com.redislabs.redisgraph.RedisGraphContexted; +import com.redislabs.redisgraph.RedisGraphContext; import com.redislabs.redisgraph.ResultSet; import com.redislabs.redisgraph.impl.Utils; import com.redislabs.redisgraph.impl.graph_cache.RedisGraphCaches; @@ -12,10 +12,10 @@ import java.util.List; /** - * An implementaion of RedisGraphContexted. Allows sending RedisGraph and some Redis commands, + * An implementaion of RedisGraphContext. Allows sending RedisGraph and some Redis commands, * within a specific connection context */ -public class ContextedRedisGraph extends AbstractRedisGraph implements RedisGraphContexted, RedisGraphCacheHolder { +public class ContextedRedisGraph extends AbstractRedisGraph implements RedisGraphContext, RedisGraphCacheHolder { private Jedis connectionContext; private RedisGraphCaches caches; diff --git a/src/main/java/com/redislabs/redisgraph/impl/api/RedisGraph.java b/src/main/java/com/redislabs/redisgraph/impl/api/RedisGraph.java index 900e32c..d3bea57 100644 --- a/src/main/java/com/redislabs/redisgraph/impl/api/RedisGraph.java +++ b/src/main/java/com/redislabs/redisgraph/impl/api/RedisGraph.java @@ -1,7 +1,7 @@ package com.redislabs.redisgraph.impl.api; -import com.redislabs.redisgraph.RedisGraphContexted; -import com.redislabs.redisgraph.RedisGraphGeneralContext; +import com.redislabs.redisgraph.RedisGraphContext; +import com.redislabs.redisgraph.RedisGraphContextGenerator; import com.redislabs.redisgraph.ResultSet; import com.redislabs.redisgraph.impl.graph_cache.RedisGraphCaches; import redis.clients.jedis.Jedis; @@ -12,7 +12,7 @@ /** * */ -public class RedisGraph extends AbstractRedisGraph implements RedisGraphGeneralContext { +public class RedisGraph extends AbstractRedisGraph implements RedisGraphContextGenerator { private final Pool client; private RedisGraphCaches caches = new RedisGraphCaches(); @@ -99,7 +99,7 @@ public String deleteGraph(String graphId) { * @return ContextedRedisGraph */ @Override - public RedisGraphContexted getContextedAPI() { + public RedisGraphContext getContext() { ContextedRedisGraph contextedRedisGraph = new ContextedRedisGraph(getConnection()); contextedRedisGraph.setRedisGraphCaches(this.caches); return contextedRedisGraph; diff --git a/src/test/java/com/redislabs/redisgraph/RedisGraphAPITest.java b/src/test/java/com/redislabs/redisgraph/RedisGraphAPITest.java index 6c5514e..59e35e3 100644 --- a/src/test/java/com/redislabs/redisgraph/RedisGraphAPITest.java +++ b/src/test/java/com/redislabs/redisgraph/RedisGraphAPITest.java @@ -1,7 +1,6 @@ package com.redislabs.redisgraph; -import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.NoSuchElementException; @@ -23,7 +22,7 @@ import static com.redislabs.redisgraph.Header.ResultSetColumnTypes.*; public class RedisGraphAPITest { - private RedisGraphGeneralContext api; + private RedisGraphContextGenerator api; public RedisGraphAPITest() { } @@ -36,11 +35,7 @@ public void createApi(){ public void deleteGraph() { api.deleteGraph("social"); - try { - api.close(); - } catch (IOException e) { - e.printStackTrace(); - } + api.close(); } @@ -504,123 +499,123 @@ public void testEscapedQuery() { @Test public void testMultiExec(){ - RedisGraphTransaction transaction = api.getContextedAPI().multi(); - - transaction.set("x", "1"); - transaction.query("social", "CREATE (:Person {name:'a'})"); - transaction.query("g", "CREATE (:Person {name:'a'})"); - transaction.incr("x"); - transaction.get("x"); - transaction.query("social", "MATCH (n:Person) RETURN n"); - transaction.deleteGraph("g"); - transaction.callProcedure("social", "db.labels"); - List results = transaction.exec(); - - // Redis set command - Assert.assertEquals(String.class, results.get(0).getClass()); - Assert.assertEquals("OK", results.get(0)); - - // Redis graph command - Assert.assertEquals(ResultSetImpl.class, results.get(1).getClass()); - ResultSet resultSet = (ResultSet) results.get(1); - Assert.assertEquals(1, resultSet.getStatistics().nodesCreated()); - Assert.assertEquals(1, resultSet.getStatistics().propertiesSet()); - - - Assert.assertEquals(ResultSetImpl.class, results.get(2).getClass()); - resultSet = (ResultSet) results.get(2); - Assert.assertEquals(1, resultSet.getStatistics().nodesCreated()); - Assert.assertEquals(1, resultSet.getStatistics().propertiesSet()); - - // Redis incr command - Assert.assertEquals(Long.class, results.get(3).getClass()); - Assert.assertEquals((long)2, results.get(3)); + try (RedisGraphContext c = api.getContext()) { + RedisGraphTransaction transaction = api.getContext().multi(); + + transaction.set("x", "1"); + transaction.query("social", "CREATE (:Person {name:'a'})"); + transaction.query("g", "CREATE (:Person {name:'a'})"); + transaction.incr("x"); + transaction.get("x"); + transaction.query("social", "MATCH (n:Person) RETURN n"); + transaction.deleteGraph("g"); + transaction.callProcedure("social", "db.labels"); + List results = transaction.exec(); + + // Redis set command + Assert.assertEquals(String.class, results.get(0).getClass()); + Assert.assertEquals("OK", results.get(0)); + + // Redis graph command + Assert.assertEquals(ResultSetImpl.class, results.get(1).getClass()); + ResultSet resultSet = (ResultSet) results.get(1); + Assert.assertEquals(1, resultSet.getStatistics().nodesCreated()); + Assert.assertEquals(1, resultSet.getStatistics().propertiesSet()); + + + Assert.assertEquals(ResultSetImpl.class, results.get(2).getClass()); + resultSet = (ResultSet) results.get(2); + Assert.assertEquals(1, resultSet.getStatistics().nodesCreated()); + Assert.assertEquals(1, resultSet.getStatistics().propertiesSet()); + + // Redis incr command + Assert.assertEquals(Long.class, results.get(3).getClass()); + Assert.assertEquals((long)2, results.get(3)); + + // Redis get command + Assert.assertEquals(String.class, results.get(4).getClass()); + Assert.assertEquals("2", results.get(4)); + + // Graph query result + Assert.assertEquals(ResultSetImpl.class, results.get(5).getClass()); + resultSet = (ResultSet) results.get(5); - // Redis get command - Assert.assertEquals(String.class, results.get(4).getClass()); - Assert.assertEquals("2", results.get(4)); - - // Graph query result - Assert.assertEquals(ResultSetImpl.class, results.get(5).getClass()); - resultSet = (ResultSet) results.get(5); - - Assert.assertNotNull(resultSet.getHeader()); - Header header = resultSet.getHeader(); + Assert.assertNotNull(resultSet.getHeader()); + Header header = resultSet.getHeader(); - List schemaNames = header.getSchemaNames(); - List schemaTypes = header.getSchemaTypes(); + List schemaNames = header.getSchemaNames(); + List schemaTypes = header.getSchemaTypes(); - Assert.assertNotNull(schemaNames); - Assert.assertNotNull(schemaTypes); + Assert.assertNotNull(schemaNames); + Assert.assertNotNull(schemaTypes); - Assert.assertEquals(1, schemaNames.size()); - Assert.assertEquals(1, schemaTypes.size()); + Assert.assertEquals(1, schemaNames.size()); + Assert.assertEquals(1, schemaTypes.size()); - Assert.assertEquals("n", schemaNames.get(0)); + Assert.assertEquals("n", schemaNames.get(0)); - Assert.assertEquals(COLUMN_NODE, schemaTypes.get(0)); + Assert.assertEquals(COLUMN_NODE, schemaTypes.get(0)); - Property nameProperty = new Property("name", ResultSet.ResultSetScalarTypes.PROPERTY_STRING, "a"); + Property nameProperty = new Property("name", ResultSet.ResultSetScalarTypes.PROPERTY_STRING, "a"); - Node expectedNode = new Node(); - expectedNode.setId(0); - expectedNode.addLabel("Person"); - expectedNode.addProperty(nameProperty); - // see that the result were pulled from the right graph - Assert.assertEquals(1, resultSet.size()); - Assert.assertTrue(resultSet.hasNext()); - Record record = resultSet.next(); - Assert.assertFalse(resultSet.hasNext()); - Assert.assertEquals(Arrays.asList("n"), record.keys()); - Assert.assertEquals(expectedNode, record.getValue("n")); - - // Graph delete - Assert.assertTrue(((String)results.get(6)).startsWith("Graph removed")); + Node expectedNode = new Node(); + expectedNode.setId(0); + expectedNode.addLabel("Person"); + expectedNode.addProperty(nameProperty); + // see that the result were pulled from the right graph + Assert.assertEquals(1, resultSet.size()); + Assert.assertTrue(resultSet.hasNext()); + Record record = resultSet.next(); + Assert.assertFalse(resultSet.hasNext()); + Assert.assertEquals(Arrays.asList("n"), record.keys()); + Assert.assertEquals(expectedNode, record.getValue("n")); + // Graph delete + Assert.assertTrue(((String)results.get(6)).startsWith("Graph removed")); - Assert.assertEquals(ResultSetImpl.class, results.get(7).getClass()); - resultSet = (ResultSet) results.get(7); - Assert.assertNotNull(resultSet.getHeader()); - header = resultSet.getHeader(); + Assert.assertEquals(ResultSetImpl.class, results.get(7).getClass()); + resultSet = (ResultSet) results.get(7); + Assert.assertNotNull(resultSet.getHeader()); + header = resultSet.getHeader(); - schemaNames = header.getSchemaNames(); - schemaTypes = header.getSchemaTypes(); - Assert.assertNotNull(schemaNames); - Assert.assertNotNull(schemaTypes); + schemaNames = header.getSchemaNames(); + schemaTypes = header.getSchemaTypes(); - Assert.assertEquals(1, schemaNames.size()); - Assert.assertEquals(1, schemaTypes.size()); + Assert.assertNotNull(schemaNames); + Assert.assertNotNull(schemaTypes); - Assert.assertEquals("label", schemaNames.get(0)); + Assert.assertEquals(1, schemaNames.size()); + Assert.assertEquals(1, schemaTypes.size()); - Assert.assertEquals(COLUMN_SCALAR, schemaTypes.get(0)); + Assert.assertEquals("label", schemaNames.get(0)); - Assert.assertEquals(1, resultSet.size()); - Assert.assertTrue(resultSet.hasNext()); - record = resultSet.next(); - Assert.assertFalse(resultSet.hasNext()); - Assert.assertEquals(Arrays.asList("label"), record.keys()); - Assert.assertEquals("Person", record.getValue("label")); + Assert.assertEquals(COLUMN_SCALAR, schemaTypes.get(0)); + Assert.assertEquals(1, resultSet.size()); + Assert.assertTrue(resultSet.hasNext()); + record = resultSet.next(); + Assert.assertFalse(resultSet.hasNext()); + Assert.assertEquals(Arrays.asList("label"), record.keys()); + Assert.assertEquals("Person", record.getValue("label")); + } } @Test - public void testContextedAPI(){ + public void testContextedAPI() { String name = "roi"; int age = 32; double doubleValue = 3.14; - boolean boolValue = true; + boolean boolValue = true; String place = "TLV"; int since = 2000; - Property nameProperty = new Property("name", ResultSet.ResultSetScalarTypes.PROPERTY_STRING, name); Property ageProperty = new Property("age", ResultSet.ResultSetScalarTypes.PROPERTY_INTEGER, age); Property doubleProperty = new Property("doubleValue", ResultSet.ResultSetScalarTypes.PROPERTY_DOUBLE, doubleValue); @@ -651,76 +646,74 @@ public void testContextedAPI(){ expectedEdge.addProperty(falseBooleanProperty); expectedEdge.addProperty(nullProperty); - RedisGraphContexted c = api.getContextedAPI(); + try (RedisGraphContext c = api.getContext()) { + Assert.assertNotNull(c.query("social", "CREATE (:person{name:%s',age:%d, doubleValue:%f, boolValue:%b, nullValue:null})", name, age, doubleValue, boolValue)); + Assert.assertNotNull(c.query("social", "CREATE (:person{name:'amit',age:30})")); + Assert.assertNotNull(c.query("social", "MATCH (a:person), (b:person) WHERE (a.name = 'roi' AND b.name='amit') " + + "CREATE (a)-[:knows{place:'TLV', since:2000,doubleValue:3.14, boolValue:false, nullValue:null}]->(b)")); - Assert.assertNotNull(c.query("social", "CREATE (:person{name:%s',age:%d, doubleValue:%f, boolValue:%b, nullValue:null})", name, age, doubleValue, boolValue)); - Assert.assertNotNull(c.query("social", "CREATE (:person{name:'amit',age:30})")); - Assert.assertNotNull(c.query("social", "MATCH (a:person), (b:person) WHERE (a.name = 'roi' AND b.name='amit') " + - "CREATE (a)-[:knows{place:'TLV', since:2000,doubleValue:3.14, boolValue:false, nullValue:null}]->(b)")); + ResultSet resultSet = c.query("social", "MATCH (a:person)-[r:knows]->(b:person) RETURN a,r, " + + "a.name, a.age, a.doubleValue, a.boolValue, a.nullValue, " + + "r.place, r.since, r.doubleValue, r.boolValue, r.nullValue"); + Assert.assertNotNull(resultSet); - ResultSet resultSet = c.query("social", "MATCH (a:person)-[r:knows]->(b:person) RETURN a,r, " + - "a.name, a.age, a.doubleValue, a.boolValue, a.nullValue, " + - "r.place, r.since, r.doubleValue, r.boolValue, r.nullValue"); - Assert.assertNotNull(resultSet); + Assert.assertEquals(0, resultSet.getStatistics().nodesCreated()); + Assert.assertEquals(0, resultSet.getStatistics().nodesDeleted()); + Assert.assertEquals(0, resultSet.getStatistics().labelsAdded()); + Assert.assertEquals(0, resultSet.getStatistics().propertiesSet()); + Assert.assertEquals(0, resultSet.getStatistics().relationshipsCreated()); + Assert.assertEquals(0, resultSet.getStatistics().relationshipsDeleted()); + Assert.assertNotNull(resultSet.getStatistics().getStringValue(Label.QUERY_INTERNAL_EXECUTION_TIME)); - Assert.assertEquals(0, resultSet.getStatistics().nodesCreated()); - Assert.assertEquals(0, resultSet.getStatistics().nodesDeleted()); - Assert.assertEquals(0, resultSet.getStatistics().labelsAdded()); - Assert.assertEquals(0, resultSet.getStatistics().propertiesSet()); - Assert.assertEquals(0, resultSet.getStatistics().relationshipsCreated()); - Assert.assertEquals(0, resultSet.getStatistics().relationshipsDeleted()); - Assert.assertNotNull(resultSet.getStatistics().getStringValue(Label.QUERY_INTERNAL_EXECUTION_TIME)); + Assert.assertEquals(1, resultSet.size()); + Assert.assertTrue(resultSet.hasNext()); + Record record = resultSet.next(); + Assert.assertFalse(resultSet.hasNext()); - Assert.assertEquals(1, resultSet.size()); - Assert.assertTrue(resultSet.hasNext()); - Record record = resultSet.next(); - Assert.assertFalse(resultSet.hasNext()); + Node node = record.getValue(0); + Assert.assertNotNull(node); - Node node = record.getValue(0); - Assert.assertNotNull(node); + Assert.assertEquals(expectedNode, node); - Assert.assertEquals(expectedNode, node); + node = record.getValue("a"); + Assert.assertEquals(expectedNode, node); - node = record.getValue("a"); - Assert.assertEquals(expectedNode, node); + Edge edge = record.getValue(1); + Assert.assertNotNull(edge); + Assert.assertEquals(expectedEdge, edge); - Edge edge = record.getValue(1); - Assert.assertNotNull(edge); - Assert.assertEquals(expectedEdge, edge); + edge = record.getValue("r"); + Assert.assertEquals(expectedEdge, edge); - edge = record.getValue("r"); - Assert.assertEquals(expectedEdge, edge); + Assert.assertEquals(Arrays.asList("a", "r", "a.name", "a.age", "a.doubleValue", "a.boolValue", "a.nullValue", + "r.place", "r.since", "r.doubleValue", "r.boolValue", "r.nullValue"), record.keys()); - Assert.assertEquals(Arrays.asList("a", "r", "a.name", "a.age", "a.doubleValue", "a.boolValue", "a.nullValue", - "r.place", "r.since", "r.doubleValue", "r.boolValue", "r.nullValue"), record.keys()); + Assert.assertEquals(Arrays.asList(expectedNode, expectedEdge, + name, age, doubleValue, true, null, + place, since, doubleValue, false, null), + record.values()); - Assert.assertEquals(Arrays.asList(expectedNode, expectedEdge, - name, age, doubleValue, true, null, - place, since, doubleValue, false, null), - record.values()); + Node a = record.getValue("a"); + for (String propertyName : expectedNode.getEntityPropertyNames()) { + Assert.assertEquals(expectedNode.getProperty(propertyName), a.getProperty(propertyName)); + } - Node a = record.getValue("a"); - for (String propertyName : expectedNode.getEntityPropertyNames()){ - Assert.assertEquals(expectedNode.getProperty(propertyName) ,a.getProperty(propertyName)); + Assert.assertEquals("roi", record.getString(2)); + Assert.assertEquals("32", record.getString(3)); + Assert.assertEquals(32L, ((Integer) (record.getValue(3))).longValue()); + Assert.assertEquals(32L, ((Integer) record.getValue("a.age")).longValue()); + Assert.assertEquals("roi", record.getString("a.name")); + Assert.assertEquals("32", record.getString("a.age")); } - - Assert.assertEquals( "roi", record.getString(2)); - Assert.assertEquals( "32", record.getString(3)); - Assert.assertEquals( 32L, ((Integer)(record.getValue(3))).longValue()); - Assert.assertEquals( 32L, ((Integer)record.getValue("a.age")).longValue()); - Assert.assertEquals( "roi", record.getString("a.name")); - Assert.assertEquals( "32", record.getString("a.age")); - - } @Test public void testWriteTransactionWatch(){ - RedisGraphContexted c1 = api.getContextedAPI(); - RedisGraphContexted c2 = api.getContextedAPI(); + RedisGraphContext c1 = api.getContext(); + RedisGraphContext c2 = api.getContext(); c1.watch("social"); RedisGraphTransaction t1 = c1.multi(); @@ -730,25 +723,15 @@ public void testWriteTransactionWatch(){ c2.query("social", "CREATE (:Person {name:'b'})"); List returnValue = t1.exec(); Assert.assertNull(returnValue); - - try { - c1.close(); - } catch (IOException e) { - e.printStackTrace(); - } - try { - c2.close(); - } catch (IOException e) { - e.printStackTrace(); - } - + c1.close(); + c2.close(); } @Test public void testReadTransactionWatch(){ - RedisGraphContexted c1 = api.getContextedAPI(); - RedisGraphContexted c2 = api.getContextedAPI(); + RedisGraphContext c1 = api.getContext(); + RedisGraphContext c2 = api.getContext(); Assert.assertNotEquals(c1.getConnectionContext(), c2.getConnectionContext()); c1.query("social", "CREATE (:Person {name:'a'})"); c1.watch("social"); @@ -759,17 +742,7 @@ public void testReadTransactionWatch(){ List returnValue = t1.exec(); Assert.assertNotNull(returnValue); - - try { - c1.close(); - } catch (IOException e) { - e.printStackTrace(); - } - try { - c2.close(); - } catch (IOException e) { - e.printStackTrace(); - } - + c1.close(); + c2.close(); } }