diff --git a/pom.xml b/pom.xml index 1ee0d50..156d92c 100644 --- a/pom.xml +++ b/pom.xml @@ -11,25 +11,49 @@ com.hazelcast - hazelcast-enterprise-client - 3.12.6 + hazelcast-enterprise + 5.4.0 + + UTF-8 + + + + com.hazelcast.cloud + hazelcast-cloud-maven-plugin + 0.2.0 + + YOUR_DISCOVERY_URL + YOUR_CLUSTER_ID + + + + org.apache.maven.plugins maven-compiler-plugin + 3.10.1 - 1.8 - 1.8 + 17 + 17 + UTF-8 + + + org.projectlombok + lombok + 1.18.30 + + org.codehaus.mojo exec-maven-plugin - 1.6.0 + 3.1.0 client @@ -56,9 +80,12 @@ - hazelcast-ee - Sonatype Repository - https://repository.hazelcast.com/release + Hazelcast Private Release Repository + https://repository.hazelcast.com/release/ + + + Hazelcast Private Snapshot Repository + https://repository.hazelcast.com/snapshot/ diff --git a/src/main/java/com/hazelcast/cloud/Client.java b/src/main/java/com/hazelcast/cloud/Client.java index dd7d390..754ca6b 100644 --- a/src/main/java/com/hazelcast/cloud/Client.java +++ b/src/main/java/com/hazelcast/cloud/Client.java @@ -1,45 +1,175 @@ +/* + * Copyright (c) 2008-2023, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hazelcast.cloud; import com.hazelcast.client.HazelcastClient; import com.hazelcast.client.config.ClientConfig; -import com.hazelcast.client.spi.properties.ClientProperty; -import com.hazelcast.config.GroupConfig; +import com.hazelcast.cloud.jobs.UpperCaseFunction; +import com.hazelcast.cloud.model.City; import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.core.IMap; - -import java.util.Random; +import com.hazelcast.jet.config.JobConfig; +import com.hazelcast.jet.pipeline.BatchSource; +import com.hazelcast.jet.pipeline.Pipeline; +import com.hazelcast.jet.pipeline.Sinks; +import com.hazelcast.jet.pipeline.test.TestSources; +import com.hazelcast.map.IMap; +import com.hazelcast.sql.SqlResult; +import com.hazelcast.sql.SqlRow; +import com.hazelcast.sql.SqlService; /** * This is boilerplate application that configures client to connect Hazelcast Cloud cluster. - * After successful connection, it puts random entries into the map. *

- * See: https://docs.cloud.hazelcast.com/docs/java-client + * See: https://docs.hazelcast.com/cloud/get-started */ public class Client { public static void main(String[] args) { ClientConfig config = new ClientConfig(); - config.setGroupConfig(new GroupConfig("YOUR_CLUSTER_NAME", "YOUR_CLUSTER_PASSWORD")); - config.setProperty("hazelcast.client.statistics.enabled", "true"); - config.setProperty(ClientProperty.HAZELCAST_CLOUD_DISCOVERY_TOKEN.getName(), "YOUR_CLUSTER_DISCOVERY_TOKEN"); + config.getNetworkConfig().getCloudConfig() + .setDiscoveryToken("YOUR_CLUSTER_DISCOVERY_TOKEN") + .setEnabled(true); config.setProperty("hazelcast.client.cloud.url", "YOUR_DISCOVERY_URL"); - + config.setClusterName("YOUR_CLUSTER_NAME"); HazelcastInstance client = HazelcastClient.newHazelcastClient(config); - System.out.println("Connection Successful!"); - System.out.println("Now the map named 'map' will be filled with random entries."); - - IMap map = client.getMap("map"); - Random random = new Random(); - int iterationCounter = 0; - while (true) { - int randomKey = random.nextInt(100_000); - map.put("key-" + randomKey, "value-" + randomKey); - map.get("key-" + random.nextInt(100_000)); - if (++iterationCounter == 10) { - iterationCounter = 0; - System.out.println("Current map size: " + map.size()); + try { + createMapping(client.getSql()); + insertCities(client); + fetchCities(client.getSql()); + jetJobExample(client); + } finally { + client.shutdown(); + } + } + + private static void createMapping(SqlService sqlService) { + // See: https://docs.hazelcast.com/hazelcast/latest/sql/mapping-to-maps#compact-objects + System.out.print("\nCreating mapping for cities..."); + + String mappingSql = "" + + "CREATE OR REPLACE MAPPING cities(" + + " __key INT," + + " country VARCHAR," + + " city VARCHAR," + + " population INT" + + ") TYPE IMap" + + " OPTIONS (" + + " 'keyFormat' = 'int'," + + " 'valueFormat' = 'compact'," + + " 'valueCompactTypeName' = 'city'" + + " )"; + + try (SqlResult ignored = sqlService.execute(mappingSql)) { + System.out.print("OK."); + } catch (Exception ex) { + System.out.print("FAILED. " + ex.getMessage()); + } + } + + private static void insertCities(HazelcastInstance client) { + try { + System.out.print("\nCleaning up the 'cities' map..."); + client.getSql().execute("DELETE FROM cities"); + System.out.print("Cleanup...OK."); + System.out.print("\nInserting cities into 'cities' map..."); + + String insertQuery = "INSERT INTO cities " + + "(__key, city, country, population) VALUES" + + "(1, 'London', 'United Kingdom', 9540576)," + + "(2, 'Manchester', 'United Kingdom', 2770434)," + + "(3, 'New York', 'United States', 19223191)," + + "(4, 'Los Angeles', 'United States', 3985520)," + + "(5, 'Istanbul', 'Türkiye', 15636243)," + + "(6, 'Ankara', 'Türkiye', 5309690)," + + "(7, 'Sao Paulo ', 'Brazil', 22429800)"; + + SqlResult result = client.getSql().execute(insertQuery); + System.out.print("Insert...OK..."); + } catch (Exception ex) { + System.out.print("FAILED. " + ex.getMessage()); + } + + // Let's also add a city as object. + IMap map = client.getMap("cities"); + + City c = new City("Brazil", "Rio de Janeiro", 13634274); + System.out.print("\nPutting a city into 'cities' map..."); + map.put(8, c); + System.out.print("OK."); + } + + private static void fetchCities(SqlService sqlService) { + + System.out.print("\nFetching cities via SQL..."); + + try (SqlResult result = sqlService.execute("SELECT __key, this FROM cities")) { + System.out.print("OK.\n"); + System.out.println("--Results of 'SELECT __key, this FROM cities'"); + + System.out.printf("%4s | %20s | %20s | %15s |%n", "id", "country", "city", "population"); + for (SqlRow row : result) { + int id = row.getObject("__key"); + City c = row.getObject("this"); + System.out.printf("%4s | %20s | %20s | %15s |%n", + id, + c.getCountry(), + c.getCity(), + c.getPopulation() + ); } + } catch (Exception ex) { + System.out.print("FAILED. " + ex.getMessage()); } + + System.out.println("\n" + + "!! Hint !! You can execute your SQL queries on your Hazelcast Cloud cluster using the \"SQL Broswer\" UI.\n" + + "1. Start one of the preloaded demos in your Trial Experience.\n" + + "2. This will open the 'SQL Browser'.\n" + + "3. Add a new Tab.\n" + + "4. Try to execute 'SELECT * FROM cities'.\n" + ); + } + + /** + * This example shows how to submit simple Jet job which uses logger as a sink. You will be able to see the results + * of job execution in the Hazelcast cluster logs. + * + * @param client- a {@link HazelcastInstance} client. + */ + private static void jetJobExample(HazelcastInstance client) { + // See: https://docs.hazelcast.com/hazelcast/5.2/pipelines/submitting-jobs + System.out.println("Submitting Jet job"); + + BatchSource items = TestSources.items( + "United States", "Türkiye", "United Kingdom", "Poland", "Ukraine" + ); + + Pipeline pipeline = Pipeline.create() + .readFrom(items) + .map(new UpperCaseFunction()) + .writeTo(Sinks.logger()) // Results will be visible on the server logs. + .getPipeline(); + + JobConfig jobConfig = new JobConfig() + .addClass(UpperCaseFunction.class); + + client.getJet().newJob(pipeline, jobConfig); + + System.out.println("Jet job submitted. \nYou can see the results in the logs. Go to your Hazelcast Cloud cluster, and click the 'Logs'."); } } diff --git a/src/main/java/com/hazelcast/cloud/ClientWithSsl.java b/src/main/java/com/hazelcast/cloud/ClientWithSsl.java index 773f3d8..c018905 100644 --- a/src/main/java/com/hazelcast/cloud/ClientWithSsl.java +++ b/src/main/java/com/hazelcast/cloud/ClientWithSsl.java @@ -1,54 +1,194 @@ +/* + * Copyright (c) 2008-2023, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.hazelcast.cloud; +import java.util.Properties; + import com.hazelcast.client.HazelcastClient; import com.hazelcast.client.config.ClientConfig; -import com.hazelcast.client.spi.properties.ClientProperty; -import com.hazelcast.config.GroupConfig; +import com.hazelcast.cloud.jobs.UpperCaseFunction; +import com.hazelcast.cloud.model.City; +import com.hazelcast.cloud.model.CitySerializer; import com.hazelcast.config.SSLConfig; import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.core.IMap; - -import java.util.Properties; -import java.util.Random; +import com.hazelcast.jet.config.JobConfig; +import com.hazelcast.jet.pipeline.BatchSource; +import com.hazelcast.jet.pipeline.Pipeline; +import com.hazelcast.jet.pipeline.Sinks; +import com.hazelcast.jet.pipeline.test.TestSources; +import com.hazelcast.map.IMap; +import com.hazelcast.sql.SqlResult; +import com.hazelcast.sql.SqlRow; +import com.hazelcast.sql.SqlService; /** * This is boilerplate application that configures client to connect Hazelcast Cloud cluster. - * After successful connection, it puts random entries into the map. *

- * See: https://docs.cloud.hazelcast.com/docs/java-client + * See: https://docs.hazelcast.com/cloud/get-started */ public class ClientWithSsl { public static void main(String[] args) throws Exception { + // Configure the client. ClassLoader classLoader = ClientWithSsl.class.getClassLoader(); Properties props = new Properties(); props.setProperty("javax.net.ssl.keyStore", classLoader.getResource("client.keystore").toURI().getPath()); props.setProperty("javax.net.ssl.keyStorePassword", "YOUR_SSL_PASSWORD"); - props.setProperty("javax.net.ssl.trustStore", classLoader.getResource("client.truststore").toURI().getPath()); + props.setProperty("javax.net.ssl.trustStore", + classLoader.getResource("client.truststore").toURI().getPath()); props.setProperty("javax.net.ssl.trustStorePassword", "YOUR_SSL_PASSWORD"); ClientConfig config = new ClientConfig(); config.getNetworkConfig().setSSLConfig(new SSLConfig().setEnabled(true).setProperties(props)); - config.setGroupConfig(new GroupConfig("YOUR_CLUSTER_NAME", "YOUR_CLUSTER_PASSWORD")); - config.setProperty("hazelcast.client.statistics.enabled", "true"); - config.setProperty(ClientProperty.HAZELCAST_CLOUD_DISCOVERY_TOKEN.getName(), "YOUR_CLUSTER_DISCOVERY_TOKEN"); + config.getNetworkConfig().getCloudConfig() + .setDiscoveryToken("YOUR_CLUSTER_DISCOVERY_TOKEN") + .setEnabled(true); config.setProperty("hazelcast.client.cloud.url", "YOUR_DISCOVERY_URL"); + config.setClusterName("YOUR_CLUSTER_NAME"); - HazelcastInstance client = HazelcastClient.newHazelcastClient(config); + // Register serializer of the City. + config.getSerializationConfig().getCompactSerializationConfig().addSerializer(new CitySerializer()); + System.out.println("Connect Hazelcast Cloud with TLS"); + HazelcastInstance client = HazelcastClient.newHazelcastClient(config); System.out.println("Connection Successful!"); - System.out.println("Now the map named 'map' will be filled with random entries."); - - IMap map = client.getMap("map"); - Random random = new Random(); - int iterationCounter = 0; - while (true) { - int randomKey = random.nextInt(100_000); - map.put("key-" + randomKey, "value-" + randomKey); - map.get("key-" + random.nextInt(100_000)); - if (++iterationCounter == 10) { - iterationCounter = 0; - System.out.println("Current map size: " + map.size()); + + try { + createMapping(client.getSql()); + insertCities(client); + fetchCities(client.getSql()); + jetJobExample(client); + } finally { + client.shutdown(); + } + } + + private static void createMapping(SqlService sqlService) { + // See: https://docs.hazelcast.com/hazelcast/latest/sql/mapping-to-maps#compact-objects + System.out.print("\nCreating mapping for cities..."); + + String mappingSql = "" + + "CREATE OR REPLACE MAPPING cities(" + + " __key INT," + + " country VARCHAR," + + " city VARCHAR," + + " population INT" + + ") TYPE IMap" + + " OPTIONS (" + + " 'keyFormat' = 'int'," + + " 'valueFormat' = 'compact'," + + " 'valueCompactTypeName' = 'city'" + + " )"; + + try (SqlResult ignored = sqlService.execute(mappingSql)) { + System.out.print("OK."); + } catch (Exception ex) { + System.out.print("FAILED. " + ex.getMessage()); + } + } + + private static void insertCities(HazelcastInstance client) { + try { + System.out.print("\nCleaning up the 'cities' map..."); + client.getSql().execute("DELETE FROM cities"); + System.out.print("Cleanup...OK."); + System.out.print("\nInserting cities into 'cities' map..."); + + String insertQuery = "INSERT INTO cities " + + "(__key, city, country, population) VALUES" + + "(1, 'London', 'United Kingdom', 9540576)," + + "(2, 'Manchester', 'United Kingdom', 2770434)," + + "(3, 'New York', 'United States', 19223191)," + + "(4, 'Los Angeles', 'United States', 3985520)," + + "(5, 'Istanbul', 'Türkiye', 15636243)," + + "(6, 'Ankara', 'Türkiye', 5309690)," + + "(7, 'Sao Paulo ', 'Brazil', 22429800)"; + + SqlResult result = client.getSql().execute(insertQuery); + System.out.print("Insert...OK."); + } catch (Exception ex) { + System.out.print("FAILED. " + ex.getMessage()); + } + + // Let's also add a city as object. + IMap map = client.getMap("cities"); + + City c = new City("Brazil", "Rio de Janeiro", 13634274); + System.out.print("\nPutting a city into 'cities' map..."); + map.put(8, c); + System.out.print("OK."); + } + + private static void fetchCities(SqlService sqlService) { + + System.out.print("\nFetching cities via SQL..."); + + try (SqlResult result = sqlService.execute("SELECT __key, this FROM cities")) { + System.out.print("OK.\n"); + System.out.println("--Results of 'SELECT __key, this FROM cities'"); + + System.out.printf("%4s | %20s | %20s | %15s |%n", "id", "country", "city", "population"); + for (SqlRow row : result) { + int id = row.getObject("__key"); + City c = row.getObject("this"); + System.out.printf("%4s | %20s | %20s | %15s |%n", + id, + c.getCountry(), + c.getCity(), + c.getPopulation() + ); } + } catch (Exception ex) { + System.out.print("FAILED. " + ex.getMessage()); } + + System.out.println("\n" + + "!! Hint !! You can execute your SQL queries on your Hazelcast Cloud cluster using the \"SQL Broswer\" UI.\n" + + "1. Start one of the preloaded demos in your Trial Experience.\n" + + "2. This will open the 'SQL Browser'.\n" + + "3. Add a new Tab.\n" + + "4. Try to execute 'SELECT * FROM cities'.\n" + ); + } + + /** + * This example shows how to submit simple Jet job which uses logger as a sink. You will be able to see the results + * of job execution in the Hazelcast cluster logs. + * + * @param client- a {@link HazelcastInstance} client. + */ + private static void jetJobExample(HazelcastInstance client) { + // See: https://docs.hazelcast.com/hazelcast/5.2/pipelines/submitting-jobs + System.out.println("Submitting Jet job"); + + BatchSource items = TestSources.items( + "United States", "Türkiye", "United Kingdom", "Poland", "Ukraine" + ); + + Pipeline pipeline = Pipeline.create() + .readFrom(items) + .map(new UpperCaseFunction()) + .writeTo(Sinks.logger()) // Results will be visible on the server logs. + .getPipeline(); + + JobConfig jobConfig = new JobConfig() + .addClass(UpperCaseFunction.class); + + client.getJet().newJob(pipeline, jobConfig); + + System.out.println("Jet job submitted. \nYou can see the results in the logs (go to your cluster page in the Hazelcast Cloud console and click the 'Logs' link) or in Management Center - Jobs section (also available through the Hazelcast Cloud cluster page)."); } } diff --git a/src/main/java/com/hazelcast/cloud/jobs/UpperCaseFunction.java b/src/main/java/com/hazelcast/cloud/jobs/UpperCaseFunction.java new file mode 100644 index 0000000..655d737 --- /dev/null +++ b/src/main/java/com/hazelcast/cloud/jobs/UpperCaseFunction.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2008-2023, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hazelcast.cloud.jobs; + +import com.hazelcast.function.FunctionEx; + +public class UpperCaseFunction implements FunctionEx { + @Override + public String applyEx(String s) { + return s.toUpperCase(); + } +} diff --git a/src/main/java/com/hazelcast/cloud/model/City.java b/src/main/java/com/hazelcast/cloud/model/City.java new file mode 100644 index 0000000..db45dd6 --- /dev/null +++ b/src/main/java/com/hazelcast/cloud/model/City.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2008-2023, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hazelcast.cloud.model; + +public final class City { + + private final String country; + + private final String city; + + private final int population; + + public City(String country, String city, int population) { + this.country = country; + this.city = city; + this.population = population; + } + + public String getCountry() { + return country; + } + + public String getCity() { + return city; + } + + public int getPopulation() { + return population; + } + +} diff --git a/src/main/java/com/hazelcast/cloud/model/CitySerializer.java b/src/main/java/com/hazelcast/cloud/model/CitySerializer.java new file mode 100644 index 0000000..a789585 --- /dev/null +++ b/src/main/java/com/hazelcast/cloud/model/CitySerializer.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2008-2023, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hazelcast.cloud.model; + +import com.hazelcast.nio.serialization.compact.CompactReader; +import com.hazelcast.nio.serialization.compact.CompactSerializer; +import com.hazelcast.nio.serialization.compact.CompactWriter; + +public class CitySerializer implements CompactSerializer { + @Override + public City read(CompactReader compactReader) { + return new City(compactReader.readString("country"), + compactReader.readString("city"), + compactReader.readInt32("population")); + } + + @Override + public void write(CompactWriter compactWriter, City city) { + compactWriter.writeString("country", city.getCountry()); + compactWriter.writeString("city", city.getCity()); + compactWriter.writeInt32("population", city.getPopulation()); + } + + @Override + public String getTypeName() { + return "city"; + } + + @Override + public Class getCompactClass() { + return City.class; + } +}