├── GCP1.png ├── GCP2.png ├── GCP3.png ├── GCP4.png ├── .gitignore ├── NOTICE ├── presence-client ├── src │ ├── eclipse │ │ └── launch │ │ │ ├── GetUsers.launch │ │ │ ├── GetUsers4.launch │ │ │ ├── PutUsers4.launch │ │ │ └── FetchUsers.launch │ └── main │ │ ├── java │ │ └── org │ │ │ └── symphonyoss │ │ │ └── s2 │ │ │ └── canon │ │ │ └── example │ │ │ └── presence │ │ │ ├── PresenceConstants.java │ │ │ ├── facade │ │ │ ├── PresenceJwtGenerator.java │ │ │ ├── IPresenceModelEntity.java │ │ │ ├── IPresence.java │ │ │ └── Presence.java │ │ │ ├── GetUsers4.java │ │ │ ├── FetchUsers.java │ │ │ ├── PutUsers4.java │ │ │ └── GetUsers.java │ │ └── canon │ │ └── presence.json └── pom.xml ├── presence-server ├── src │ ├── eclipse │ │ └── launch │ │ │ └── PresenceServer.launch │ └── main │ │ └── java │ │ └── org │ │ └── symphonyoss │ │ └── s2 │ │ └── canon │ │ └── example │ │ └── presence │ │ └── server │ │ ├── UsersUserIdTestHandler.java │ │ ├── UsersAsyncFetchHandler.java │ │ ├── UsersUserIdHandler.java │ │ ├── UsersUpdateHandler.java │ │ ├── UsersFetchHandler.java │ │ ├── UsersAsyncHandler.java │ │ ├── UsersUpdateAsyncHandler.java │ │ ├── UsersHandler.java │ │ └── PresenceServer.java └── pom.xml ├── pom.xml ├── LICENSE └── README.md /GCP1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symphonyoss/canon-example/master/GCP1.png -------------------------------------------------------------------------------- /GCP2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symphonyoss/canon-example/master/GCP2.png -------------------------------------------------------------------------------- /GCP3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symphonyoss/canon-example/master/GCP3.png -------------------------------------------------------------------------------- /GCP4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symphonyoss/canon-example/master/GCP4.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | 24 | **/*.log 25 | **/nohup.out 26 | 27 | .DS_Store 28 | .idea/** 29 | **/target/** 30 | target/** 31 | 32 | # Eclipse 33 | .metadata/** 34 | .settings/** 35 | **/.settings/** 36 | **/*.prefs 37 | **/*.project 38 | **/*.classpath 39 | 40 | workspace/** 41 | /.recommenders/ 42 | 43 | **/*.yaml 44 | 45 | */.gitignore 46 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Symphony Canon 2 | Copyright 2017-2018 Symphony Communication Services, LLC. 3 | http://symphony.com/ 4 | 5 | ======================================================================== 6 | List of Category B Licenses 7 | ======================================================================== 8 | CDDL + GPLv2 with classpath exception javax.servlet-api(javax.servlet) 9 | CDDL-GPLv2+CE mailapi(javax.mail) 10 | Mozilla Public License, Version 2.0 rhino(org.mozilla) 11 | Common Development and Distribution License (CDDL) v1.0 activation(javax.activation) 12 | ======================================================================== 13 | Eclipse Public License 1.0 14 | ======================================================================== 15 | The following components are provided under the Eclipse Public License 1.0. See project link for details. 16 | 17 | Eclipse Public License - v 1.0-GNU Lesser General Public license logback-classic(ch.qos.logback) 18 | Eclipse Public License - v 1.0-GNU Lesser General Public License logback-core(ch.qos.logback) 19 | -------------------------------------------------------------------------------- /presence-client/src/eclipse/launch/GetUsers.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /presence-client/src/eclipse/launch/GetUsers4.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /presence-client/src/eclipse/launch/PutUsers4.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /presence-client/src/eclipse/launch/FetchUsers.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /presence-server/src/eclipse/launch/PresenceServer.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /presence-client/src/main/java/org/symphonyoss/s2/canon/example/presence/PresenceConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * Copyright 2019 Symphony Communication Services, LLC. 5 | * 6 | * Licensed to The Symphony Software Foundation (SSF) under one 7 | * or more contributor license agreements. See the NOTICE file 8 | * distributed with this work for additional information 9 | * regarding copyright ownership. The ASF licenses this file 10 | * to you under the Apache License, Version 2.0 (the 11 | * "License"); you may not use this file except in compliance 12 | * with the License. You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, 17 | * software distributed under the License is distributed on an 18 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19 | * KIND, either express or implied. See the License for the 20 | * specific language governing permissions and limitations 21 | * under the License. 22 | */ 23 | 24 | package org.symphonyoss.s2.canon.example.presence; 25 | 26 | public class PresenceConstants 27 | { 28 | public static final int SERVER_PORT = 8083; 29 | public static final String SERVER_HOST = "localhost"; 30 | public static final String SERVER_URL = "http://" + SERVER_HOST + ":" + SERVER_PORT; 31 | } 32 | -------------------------------------------------------------------------------- /presence-client/src/main/java/org/symphonyoss/s2/canon/example/presence/facade/PresenceJwtGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * Copyright 2018 Symphony Communication Services, LLC. 5 | * 6 | * Licensed to The Symphony Software Foundation (SSF) under one 7 | * or more contributor license agreements. See the NOTICE file 8 | * distributed with this work for additional information 9 | * regarding copyright ownership. The ASF licenses this file 10 | * to you under the Apache License, Version 2.0 (the 11 | * "License"); you may not use this file except in compliance 12 | * with the License. You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, 17 | * software distributed under the License is distributed on an 18 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19 | * KIND, either express or implied. See the License for the 20 | * specific language governing permissions and limitations 21 | * under the License. 22 | */ 23 | 24 | package org.symphonyoss.s2.canon.example.presence.facade; 25 | 26 | import org.symphonyoss.s2.canon.runtime.jjwt.Hs256JwtGenerator; 27 | 28 | public class PresenceJwtGenerator extends Hs256JwtGenerator 29 | { 30 | public PresenceJwtGenerator() 31 | { 32 | super("Njl5qoxJAGmcOcRfDdhqe+/FP3BFV7p39htaB9Tv8hE="); 33 | withTTL(360000); 34 | withSubject(System.getProperty("user.name")); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /presence-client/src/main/java/org/symphonyoss/s2/canon/example/presence/facade/IPresenceModelEntity.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 Symphony Communication Services, LLC. 3 | * 4 | * Licensed to The Symphony Software Foundation (SSF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | * 21 | *---------------------------------------------------------------------------------------------------- 22 | * Proforma generated from 23 | * Template groupId org.symphonyoss.s2.canon 24 | * artifactId canon-template-java 25 | * Template name proforma/java/Model/I_ModelEntity.java.ftl 26 | * Template version 1.0 27 | * At 2018-02-14 18:20:04 GMT-08:00 28 | *---------------------------------------------------------------------------------------------------- 29 | */ 30 | 31 | package org.symphonyoss.s2.canon.example.presence.facade; 32 | 33 | 34 | import org.symphonyoss.s2.canon.runtime.IEntity; 35 | 36 | public interface IPresenceModelEntity extends IEntity 37 | { 38 | } 39 | /*---------------------------------------------------------------------------------------------------- 40 | * End of template proforma/java/Model/I_ModelEntity.java.ftl 41 | * End of code generation 42 | *------------------------------------------------------------------------------------------------- */ -------------------------------------------------------------------------------- /presence-server/src/main/java/org/symphonyoss/s2/canon/example/presence/server/UsersUserIdTestHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 Symphony Communication Services, LLC. 3 | * 4 | * Licensed to The Symphony Software Foundation (SSF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | * 21 | */ 22 | 23 | package org.symphonyoss.s2.canon.example.presence.server; 24 | 25 | import javax.annotation.concurrent.Immutable; 26 | 27 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresence; 28 | import org.symphonyoss.s2.canon.example.presence.canon.UserId; 29 | import org.symphonyoss.s2.canon.example.presence.canon.UsersUserIdTestPathHandler; 30 | import org.symphonyoss.s2.canon.example.presence.facade.IPresence; 31 | import org.symphonyoss.s2.canon.runtime.exception.CanonException; 32 | import org.symphonyoss.s2.canon.runtime.http.IRequestAuthenticator; 33 | import org.symphonyoss.s2.fugue.core.trace.ITraceContext; 34 | 35 | /** 36 | * Facade for Path name=UsersUserIdTest 37 | * 38 | * Manipulate a single user's presence. 39 | * 40 | * Path /users/{userId}/test 41 | * Bind Path users/ 42 | */ 43 | @Immutable 44 | public class UsersUserIdTestHandler extends UsersUserIdTestPathHandler 45 | { 46 | private IPresence presenceModel_; 47 | 48 | public UsersUserIdTestHandler(IPresence presenceModel, IRequestAuthenticator authenticator) 49 | { 50 | super(authenticator); 51 | 52 | presenceModel_ = presenceModel; 53 | } 54 | 55 | @Override 56 | public IUserPresence handleGet(String canonAuth, ITraceContext canonTrace, UserId userId) throws CanonException 57 | { 58 | return presenceModel_.getUser(userId); 59 | } 60 | } -------------------------------------------------------------------------------- /presence-server/src/main/java/org/symphonyoss/s2/canon/example/presence/server/UsersAsyncFetchHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * Copyright 2018 Symphony Communication Services, LLC. 5 | * 6 | * Licensed to The Symphony Software Foundation (SSF) under one 7 | * or more contributor license agreements. See the NOTICE file 8 | * distributed with this work for additional information 9 | * regarding copyright ownership. The ASF licenses this file 10 | * to you under the Apache License, Version 2.0 (the 11 | * "License"); you may not use this file except in compliance 12 | * with the License. You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, 17 | * software distributed under the License is distributed on an 18 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19 | * KIND, either express or implied. See the License for the 20 | * specific language governing permissions and limitations 21 | * under the License. 22 | */ 23 | 24 | package org.symphonyoss.s2.canon.example.presence.server; 25 | 26 | import java.util.concurrent.ExecutorService; 27 | 28 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresence; 29 | import org.symphonyoss.s2.canon.example.presence.canon.UserId; 30 | import org.symphonyoss.s2.canon.example.presence.canon.UsersFetchAsyncPathHandler; 31 | import org.symphonyoss.s2.canon.example.presence.facade.IPresence; 32 | import org.symphonyoss.s2.canon.runtime.exception.CanonException; 33 | import org.symphonyoss.s2.canon.runtime.http.IRequestAuthenticator; 34 | import org.symphonyoss.s2.fugue.core.trace.ITraceContext; 35 | import org.symphonyoss.s2.fugue.pipeline.IConsumer; 36 | 37 | public class UsersAsyncFetchHandler extends UsersFetchAsyncPathHandler 38 | { 39 | private IPresence presenceModel_; 40 | 41 | public UsersAsyncFetchHandler(IPresence presenceModel, ExecutorService processExecutor, ExecutorService responseExecutor, IRequestAuthenticator authenticator) 42 | { 43 | super(processExecutor, responseExecutor, authenticator); 44 | 45 | presenceModel_ = presenceModel; 46 | } 47 | 48 | @Override 49 | public void handlePost(UserId canonPayload, IConsumer canonConsumer, String canonAuth, ITraceContext canonTrace) 50 | throws CanonException 51 | { 52 | canonConsumer.consume(presenceModel_.getUser(canonPayload), canonTrace); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /presence-client/src/main/java/org/symphonyoss/s2/canon/example/presence/facade/IPresence.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 Symphony Communication Services, LLC. 3 | * 4 | * Licensed to The Symphony Software Foundation (SSF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | * 21 | *---------------------------------------------------------------------------------------------------- 22 | * Proforma generated from 23 | * Template groupId org.symphonyoss.s2.canon 24 | * artifactId canon-template-java 25 | * Template name proforma/java/Model/I_.java.ftl 26 | * Template version 1.0 27 | * At 2018-01-14 16:40:50 GMT-08:00 28 | *---------------------------------------------------------------------------------------------------- 29 | */ 30 | 31 | package org.symphonyoss.s2.canon.example.presence.facade; 32 | 33 | 34 | import java.util.Collection; 35 | 36 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresence; 37 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresenceInfo; 38 | import org.symphonyoss.s2.canon.example.presence.canon.UserId; 39 | import org.symphonyoss.s2.canon.runtime.exception.ServerErrorException; 40 | 41 | public interface IPresence 42 | { 43 | 44 | Collection getAllUsers(); 45 | 46 | IUserPresence getUser(UserId userId); 47 | void setUser(UserId userId, IUserPresenceInfo userPresenceInfo) throws ServerErrorException; 48 | } 49 | /*---------------------------------------------------------------------------------------------------- 50 | * End of template proforma/java/Model/I_.java.ftl 51 | * End of code generation 52 | *------------------------------------------------------------------------------------------------- */ -------------------------------------------------------------------------------- /presence-server/src/main/java/org/symphonyoss/s2/canon/example/presence/server/UsersUserIdHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 Symphony Communication Services, LLC. 3 | * 4 | * Licensed to The Symphony Software Foundation (SSF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | * 21 | */ 22 | 23 | package org.symphonyoss.s2.canon.example.presence.server; 24 | 25 | import javax.annotation.concurrent.Immutable; 26 | 27 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresence; 28 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresenceInfo; 29 | import org.symphonyoss.s2.canon.example.presence.canon.UserId; 30 | import org.symphonyoss.s2.canon.example.presence.canon.UsersUserIdPathHandler; 31 | import org.symphonyoss.s2.canon.example.presence.facade.IPresence; 32 | import org.symphonyoss.s2.canon.runtime.exception.ServerErrorException; 33 | import org.symphonyoss.s2.canon.runtime.http.IRequestAuthenticator; 34 | import org.symphonyoss.s2.fugue.core.trace.ITraceContext; 35 | 36 | /** 37 | * Facade for Path name=UsersUserId 38 | * 39 | * Manipulate a single user's presence. 40 | * 41 | * Path /users/{userId} 42 | * Bind Path users/ 43 | */ 44 | @Immutable 45 | public class UsersUserIdHandler extends UsersUserIdPathHandler 46 | { 47 | private IPresence presenceModel_; 48 | 49 | public UsersUserIdHandler(IPresence presenceModel, IRequestAuthenticator authenticator) 50 | { 51 | super(authenticator); 52 | 53 | presenceModel_ = presenceModel; 54 | } 55 | 56 | @Override 57 | public IUserPresence handleGet(String canonAuth, ITraceContext canonTrace, UserId userId) 58 | { 59 | IUserPresence result = presenceModel_.getUser(userId); 60 | 61 | return result; 62 | } 63 | 64 | @Override 65 | public void handlePut(IUserPresenceInfo canonPayload, String canonAuth, ITraceContext canonTrace, UserId userId) throws ServerErrorException 66 | { 67 | presenceModel_.setUser(userId, canonPayload); 68 | } 69 | } -------------------------------------------------------------------------------- /presence-server/src/main/java/org/symphonyoss/s2/canon/example/presence/server/UsersUpdateHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 Symphony Communication Services, LLC. 3 | * 4 | * Licensed to The Symphony Software Foundation (SSF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | * 21 | */ 22 | 23 | package org.symphonyoss.s2.canon.example.presence.server; 24 | 25 | import javax.annotation.concurrent.Immutable; 26 | 27 | import org.slf4j.Logger; 28 | import org.slf4j.LoggerFactory; 29 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresence; 30 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresenceList; 31 | import org.symphonyoss.s2.canon.example.presence.canon.UserPresenceInfo; 32 | import org.symphonyoss.s2.canon.example.presence.canon.UsersUpdatePathHandler; 33 | import org.symphonyoss.s2.canon.example.presence.facade.IPresence; 34 | import org.symphonyoss.s2.canon.runtime.exception.ServerErrorException; 35 | import org.symphonyoss.s2.canon.runtime.http.IRequestAuthenticator; 36 | import org.symphonyoss.s2.fugue.core.trace.ITraceContext; 37 | 38 | /** 39 | * Facade for Path name=UsersUpdate 40 | * 41 | * Manipulate a batch of users' presence. 42 | * 43 | * Path /users/update 44 | * Bind Path users/update 45 | */ 46 | @Immutable 47 | public class UsersUpdateHandler extends UsersUpdatePathHandler 48 | { 49 | private static final Logger log_ = LoggerFactory.getLogger(UsersUpdateHandler.class); 50 | 51 | private IPresence presenceModel_; 52 | 53 | public UsersUpdateHandler(IPresence presenceModel, IRequestAuthenticator authenticator) 54 | { 55 | super(authenticator); 56 | 57 | presenceModel_ = presenceModel; 58 | } 59 | 60 | @Override 61 | public void handlePost(IUserPresenceList canonPayload, String canonAuth, ITraceContext canonTrace) throws ServerErrorException 62 | { 63 | for(IUserPresence userPresence : canonPayload.getData()) 64 | { 65 | presenceModel_.setUser(userPresence.getUserId(), 66 | new UserPresenceInfo.Builder() 67 | .withStatus(userPresence.getStatus()) 68 | .withText(userPresence.getText()) 69 | .build() 70 | ); 71 | } 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /presence-server/src/main/java/org/symphonyoss/s2/canon/example/presence/server/UsersFetchHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * Copyright 2018 Symphony Communication Services, LLC. 5 | * 6 | * Licensed to The Symphony Software Foundation (SSF) under one 7 | * or more contributor license agreements. See the NOTICE file 8 | * distributed with this work for additional information 9 | * regarding copyright ownership. The ASF licenses this file 10 | * to you under the Apache License, Version 2.0 (the 11 | * "License"); you may not use this file except in compliance 12 | * with the License. You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, 17 | * software distributed under the License is distributed on an 18 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19 | * KIND, either express or implied. See the License for the 20 | * specific language governing permissions and limitations 21 | * under the License. 22 | */ 23 | 24 | package org.symphonyoss.s2.canon.example.presence.server; 25 | 26 | import java.util.LinkedList; 27 | import java.util.List; 28 | 29 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresence; 30 | import org.symphonyoss.s2.canon.example.presence.canon.UserId; 31 | import org.symphonyoss.s2.canon.example.presence.canon.UsersFetchPathHandler; 32 | import org.symphonyoss.s2.canon.example.presence.facade.IPresence; 33 | import org.symphonyoss.s2.canon.runtime.exception.CanonException; 34 | import org.symphonyoss.s2.canon.runtime.http.IRequestAuthenticator; 35 | import org.symphonyoss.s2.fugue.core.trace.ITraceContext; 36 | 37 | public class UsersFetchHandler extends UsersFetchPathHandler 38 | { 39 | private IPresence presenceModel_; 40 | 41 | public UsersFetchHandler(IPresence presenceModel, IRequestAuthenticator authenticator) 42 | { 43 | super(authenticator); 44 | 45 | presenceModel_ = presenceModel; 46 | } 47 | 48 | @Override 49 | public List handlePost(List canonPayload, String canonAuth, ITraceContext canonTrace) throws CanonException 50 | { 51 | List result = new LinkedList<>(); 52 | 53 | for(UserId userId : canonPayload) 54 | result.add(presenceModel_.getUser(userId)); 55 | 56 | return result; 57 | } 58 | 59 | // public UsersFetchHandler(IPresence presenceModel, ExecutorService processExecutor, ExecutorService responseExecutor, IRequestAuthenticator authenticator) 60 | // { 61 | // super(processExecutor, responseExecutor, authenticator); 62 | // 63 | // presenceModel_ = presenceModel; 64 | // } 65 | // 66 | // @Override 67 | // public void handlePost(UserId canonPayload, IConsumer canonConsumer, String canonAuth, ITraceContext canonTrace) 68 | // throws CanonException 69 | // { 70 | // canonConsumer.consume(presenceModel_.getUser(canonPayload), canonTrace); 71 | // } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /presence-server/src/main/java/org/symphonyoss/s2/canon/example/presence/server/UsersAsyncHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 Symphony Communication Services, LLC. 3 | * 4 | * Licensed to The Symphony Software Foundation (SSF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | * 21 | */ 22 | 23 | package org.symphonyoss.s2.canon.example.presence.server; 24 | 25 | import java.util.ArrayList; 26 | import java.util.concurrent.ExecutorService; 27 | 28 | import javax.annotation.concurrent.Immutable; 29 | 30 | import org.symphonyoss.s2.canon.example.presence.canon.Cursor; 31 | import org.symphonyoss.s2.canon.example.presence.canon.CursorLimit; 32 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresence; 33 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresencePage; 34 | import org.symphonyoss.s2.canon.example.presence.canon.UserPresencePage; 35 | import org.symphonyoss.s2.canon.example.presence.canon.UsersAsyncPathHandler; 36 | import org.symphonyoss.s2.canon.example.presence.facade.IPresence; 37 | import org.symphonyoss.s2.canon.runtime.exception.CanonException; 38 | import org.symphonyoss.s2.canon.runtime.http.IRequestAuthenticator; 39 | import org.symphonyoss.s2.fugue.core.trace.ITraceContext; 40 | import org.symphonyoss.s2.fugue.pipeline.IConsumer; 41 | 42 | /** 43 | * Facade for Path name=Users 44 | * 45 | * Fetch all users' presence. 46 | * 47 | * Path /users 48 | * Bind Path users 49 | */ 50 | @Immutable 51 | public class UsersAsyncHandler extends UsersAsyncPathHandler 52 | { 53 | private IPresence presenceModel_; 54 | 55 | public UsersAsyncHandler(IPresence presenceModel, ExecutorService processExecutor, ExecutorService responseExecutor, IRequestAuthenticator authenticator) 56 | { 57 | super(processExecutor, responseExecutor, authenticator); 58 | presenceModel_ = presenceModel; 59 | } 60 | 61 | @Override 62 | public void handleGet(IConsumer canonConsumer, String canonAuth, ITraceContext canonTrace, Cursor cursor, 63 | CursorLimit limit) throws CanonException 64 | { 65 | System.err.println("Authenticated caller is " + canonAuth); 66 | UserPresencePage.Builder builder = new UserPresencePage.Builder(); 67 | 68 | builder.withData(new ArrayList(presenceModel_.getAllUsers())); 69 | 70 | canonConsumer.consume(builder.build(), canonTrace); 71 | canonConsumer.close(); 72 | } 73 | 74 | @Override 75 | public void handlePut(String canonAuth, ITraceContext canonTrace, Cursor cursor, CursorLimit limit) throws CanonException 76 | { 77 | // TODO Auto-generated method stub 78 | 79 | } 80 | } -------------------------------------------------------------------------------- /presence-client/src/main/java/org/symphonyoss/s2/canon/example/presence/GetUsers4.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * Copyright 2018 Symphony Communication Services, LLC. 5 | * 6 | * Licensed to The Symphony Software Foundation (SSF) under one 7 | * or more contributor license agreements. See the NOTICE file 8 | * distributed with this work for additional information 9 | * regarding copyright ownership. The ASF licenses this file 10 | * to you under the Apache License, Version 2.0 (the 11 | * "License"); you may not use this file except in compliance 12 | * with the License. You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, 17 | * software distributed under the License is distributed on an 18 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19 | * KIND, either express or implied. See the License for the 20 | * specific language governing permissions and limitations 21 | * under the License. 22 | */ 23 | 24 | package org.symphonyoss.s2.canon.example.presence; 25 | 26 | import java.io.IOException; 27 | 28 | import org.apache.http.impl.client.BasicCookieStore; 29 | import org.apache.http.impl.client.CloseableHttpClient; 30 | import org.apache.http.impl.client.HttpClients; 31 | import org.slf4j.Logger; 32 | import org.slf4j.LoggerFactory; 33 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresence; 34 | import org.symphonyoss.s2.canon.example.presence.canon.PresenceHttpModelClient; 35 | import org.symphonyoss.s2.canon.example.presence.canon.PresenceModel; 36 | import org.symphonyoss.s2.canon.example.presence.canon.UserId; 37 | import org.symphonyoss.s2.canon.example.presence.canon.UsersUserIdGetHttpRequest; 38 | import org.symphonyoss.s2.canon.example.presence.facade.PresenceJwtGenerator; 39 | import org.symphonyoss.s2.canon.runtime.IModelRegistry; 40 | import org.symphonyoss.s2.canon.runtime.ModelRegistry; 41 | 42 | /** 43 | * Fetch user 4 using the REST endpoint. 44 | * 45 | * @author Bruce Skingle 46 | * 47 | */ 48 | public class GetUsers4 49 | { 50 | private static final Logger log_ = LoggerFactory.getLogger(GetUsers4.class); 51 | 52 | /** 53 | * Main. 54 | * 55 | * @param argv Command line args - ignored. 56 | * 57 | * @throws Exception If something goes wrong. This is just an example. 58 | */ 59 | public static void main(String[] argv) throws Exception 60 | { 61 | IModelRegistry registry = new ModelRegistry().withFactories(PresenceModel.FACTORIES); 62 | PresenceHttpModelClient client = new PresenceHttpModelClient(registry, PresenceConstants.SERVER_URL, null, new PresenceJwtGenerator()); 63 | 64 | UsersUserIdGetHttpRequest request = client.newUsersUserIdGetHttpRequestBuilder() 65 | .withUserId(UserId.newBuilder().build(4L)) 66 | .build(); 67 | 68 | BasicCookieStore cookieStore = new BasicCookieStore(); 69 | CloseableHttpClient httpclient = HttpClients.custom() 70 | .setDefaultCookieStore(cookieStore) 71 | .build(); 72 | try { 73 | IUserPresence p = request.execute(httpclient); 74 | 75 | System.err.printf("%10d %-20s %s%n", p.getUserId().getValue(), p.getStatus(), p.getText()); 76 | } 77 | finally 78 | { 79 | try 80 | { 81 | httpclient.close(); 82 | } 83 | catch (IOException e) 84 | { 85 | log_.error("Unable to close httpClient", e); 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /presence-server/src/main/java/org/symphonyoss/s2/canon/example/presence/server/UsersUpdateAsyncHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 Symphony Communication Services, LLC. 3 | * 4 | * Licensed to The Symphony Software Foundation (SSF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | * 21 | */ 22 | 23 | package org.symphonyoss.s2.canon.example.presence.server; 24 | 25 | import java.util.concurrent.ExecutorService; 26 | 27 | import javax.annotation.concurrent.Immutable; 28 | 29 | import org.slf4j.Logger; 30 | import org.slf4j.LoggerFactory; 31 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresence; 32 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresenceList; 33 | import org.symphonyoss.s2.canon.example.presence.canon.UserPresenceInfo; 34 | import org.symphonyoss.s2.canon.example.presence.canon.UsersUpdateAsyncPathHandler; 35 | import org.symphonyoss.s2.canon.example.presence.facade.IPresence; 36 | import org.symphonyoss.s2.canon.runtime.exception.CanonException; 37 | import org.symphonyoss.s2.canon.runtime.exception.ServerErrorException; 38 | import org.symphonyoss.s2.canon.runtime.http.IRequestAuthenticator; 39 | import org.symphonyoss.s2.fugue.core.trace.ITraceContext; 40 | 41 | /** 42 | * Facade for Path name=UsersUpdate 43 | * 44 | * Manipulate a batch of users' presence. 45 | * 46 | * Path /users/update 47 | * Bind Path users/update 48 | */ 49 | @Immutable 50 | public class UsersUpdateAsyncHandler extends UsersUpdateAsyncPathHandler 51 | { 52 | private static final Logger log_ = LoggerFactory.getLogger(UsersUpdateAsyncHandler.class); 53 | 54 | private IPresence presenceModel_; 55 | 56 | public UsersUpdateAsyncHandler(IPresence presenceModel, ExecutorService processExecutor, ExecutorService responseExecutor, IRequestAuthenticator authenticator) 57 | { 58 | super(processExecutor, responseExecutor, authenticator); 59 | 60 | presenceModel_= presenceModel; 61 | } 62 | 63 | /** 64 | * post /users/update 65 | * No summary given. 66 | * 67 | * @param canonPayload The request payload. 68 | * @param canonTrace A trace context. 69 | * 70 | * @throws CanonException If the method cannot be called 71 | */ 72 | 73 | @Override 74 | public void handlePost(IUserPresenceList canonPayload, String canonAuth, ITraceContext canonTrace) throws CanonException 75 | { 76 | for(IUserPresence userPresence : canonPayload.getData()) 77 | { 78 | presenceModel_.setUser(userPresence.getUserId(), 79 | new UserPresenceInfo.Builder() 80 | .withStatus(userPresence.getStatus()) 81 | .withText(userPresence.getText()) 82 | .build() 83 | ); 84 | 85 | throw new ServerErrorException("BROKEN FOR TEST"); 86 | } 87 | } 88 | 89 | } -------------------------------------------------------------------------------- /presence-server/src/main/java/org/symphonyoss/s2/canon/example/presence/server/UsersHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 Symphony Communication Services, LLC. 3 | * 4 | * Licensed to The Symphony Software Foundation (SSF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | * 21 | */ 22 | 23 | package org.symphonyoss.s2.canon.example.presence.server; 24 | 25 | import java.util.ArrayList; 26 | 27 | import javax.annotation.Nonnull; 28 | import javax.annotation.Nullable; 29 | import javax.annotation.concurrent.Immutable; 30 | 31 | import org.symphonyoss.s2.canon.example.presence.canon.Cursor; 32 | import org.symphonyoss.s2.canon.example.presence.canon.CursorLimit; 33 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresence; 34 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresencePage; 35 | import org.symphonyoss.s2.canon.example.presence.canon.UserPresencePage; 36 | import org.symphonyoss.s2.canon.example.presence.canon.UsersPathHandler; 37 | import org.symphonyoss.s2.canon.example.presence.facade.IPresence; 38 | import org.symphonyoss.s2.canon.runtime.exception.CanonException; 39 | import org.symphonyoss.s2.canon.runtime.http.IRequestAuthenticator; 40 | import org.symphonyoss.s2.fugue.core.trace.ITraceContext; 41 | 42 | /** 43 | * Facade for Path name=Users 44 | * 45 | * Fetch all users' presence. 46 | * 47 | * Path /users 48 | * Bind Path users 49 | */ 50 | @Immutable 51 | public class UsersHandler extends UsersPathHandler 52 | { 53 | private IPresence presenceModel_; 54 | 55 | public UsersHandler(IPresence presenceModel, IRequestAuthenticator authenticator) 56 | { 57 | super(authenticator); 58 | 59 | presenceModel_ = presenceModel; 60 | } 61 | 62 | /** 63 | * get /users 64 | * No summary given. 65 | * 66 | * @param cursor No summary given. 67 | * @param limit No summary given. 68 | * @return A UserPresencePage 69 | * @throws CanonException If the method cannot be called 70 | */ 71 | @Override 72 | public @Nonnull IUserPresencePage handleGet( 73 | String canonAuth, 74 | ITraceContext traceContext, 75 | @Nullable Cursor cursor, 76 | @Nullable CursorLimit limit 77 | ) 78 | throws CanonException 79 | { 80 | System.err.println("Authenticated caller is " + canonAuth); 81 | UserPresencePage.Builder builder = new UserPresencePage.Builder(); 82 | 83 | builder.withData(new ArrayList(presenceModel_.getAllUsers())); 84 | 85 | return builder.build(); 86 | } 87 | 88 | @Override 89 | public void handlePut( 90 | String canonAuth, ITraceContext traceContext, Cursor cursor, CursorLimit limit) throws CanonException 91 | { 92 | // TODO Auto-generated method stub 93 | 94 | } 95 | 96 | 97 | } -------------------------------------------------------------------------------- /presence-client/src/main/java/org/symphonyoss/s2/canon/example/presence/FetchUsers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * Copyright 2018 Symphony Communication Services, LLC. 5 | * 6 | * Licensed to The Symphony Software Foundation (SSF) under one 7 | * or more contributor license agreements. See the NOTICE file 8 | * distributed with this work for additional information 9 | * regarding copyright ownership. The ASF licenses this file 10 | * to you under the Apache License, Version 2.0 (the 11 | * "License"); you may not use this file except in compliance 12 | * with the License. You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, 17 | * software distributed under the License is distributed on an 18 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19 | * KIND, either express or implied. See the License for the 20 | * specific language governing permissions and limitations 21 | * under the License. 22 | */ 23 | 24 | package org.symphonyoss.s2.canon.example.presence; 25 | 26 | import java.io.IOException; 27 | import java.util.List; 28 | 29 | import org.apache.http.impl.client.BasicCookieStore; 30 | import org.apache.http.impl.client.CloseableHttpClient; 31 | import org.apache.http.impl.client.HttpClients; 32 | import org.slf4j.Logger; 33 | import org.slf4j.LoggerFactory; 34 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresence; 35 | import org.symphonyoss.s2.canon.example.presence.canon.PresenceHttpModelClient; 36 | import org.symphonyoss.s2.canon.example.presence.canon.PresenceModel; 37 | import org.symphonyoss.s2.canon.example.presence.canon.UserId; 38 | import org.symphonyoss.s2.canon.example.presence.canon.UsersFetchPostHttpRequest; 39 | import org.symphonyoss.s2.canon.example.presence.facade.PresenceJwtGenerator; 40 | import org.symphonyoss.s2.canon.runtime.IModelRegistry; 41 | import org.symphonyoss.s2.canon.runtime.ModelRegistry; 42 | 43 | /** 44 | * Fetch all users by calling a POST method. 45 | * 46 | * @author Bruce Skingle 47 | * 48 | */ 49 | public class FetchUsers 50 | { 51 | private static final Logger log_ = LoggerFactory.getLogger(FetchUsers.class); 52 | 53 | /** 54 | * Main. 55 | * 56 | * @param argv Command line args - ignored. 57 | * 58 | * @throws Exception If something goes wrong. This is just an example. 59 | */ 60 | public static void main(String[] argv) throws Exception 61 | { 62 | IModelRegistry registry = new ModelRegistry().withFactories(PresenceModel.FACTORIES); 63 | PresenceHttpModelClient client = new PresenceHttpModelClient(registry, PresenceConstants.SERVER_URL, null, new PresenceJwtGenerator()); 64 | 65 | 66 | UsersFetchPostHttpRequest request = client.newUsersFetchPostHttpRequestBuilder() 67 | .withCanonPayload(UserId.newBuilder().build(1L)) 68 | .withCanonPayload(UserId.newBuilder().build(2L)) 69 | .withCanonPayload(UserId.newBuilder().build(3L)) 70 | .build(); 71 | 72 | BasicCookieStore cookieStore = new BasicCookieStore(); 73 | CloseableHttpClient httpclient = HttpClients.custom() 74 | .setDefaultCookieStore(cookieStore) 75 | .build(); 76 | try { 77 | List result = request.execute(httpclient); 78 | 79 | for(IUserPresence p : result) 80 | { 81 | System.err.printf("%10d %-20s %s%n", p.getUserId().getValue(), p.getStatus(), p.getText()); 82 | } 83 | } 84 | finally 85 | { 86 | try 87 | { 88 | httpclient.close(); 89 | } 90 | catch (IOException e) 91 | { 92 | log_.error("Unable to close httpClient", e); 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /presence-server/src/main/java/org/symphonyoss/s2/canon/example/presence/server/PresenceServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * Copyright 2017 Symphony Communication Services, LLC. 5 | * 6 | * Licensed to The Symphony Software Foundation (SSF) under one 7 | * or more contributor license agreements. See the NOTICE file 8 | * distributed with this work for additional information 9 | * regarding copyright ownership. The SSF licenses this file 10 | * to you under the Apache License, Version 2.0 (the 11 | * "License"); you may not use this file except in compliance 12 | * with the License. You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, 17 | * software distributed under the License is distributed on an 18 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19 | * KIND, either express or implied. See the License for the 20 | * specific language governing permissions and limitations 21 | * under the License. 22 | */ 23 | 24 | package org.symphonyoss.s2.canon.example.presence.server; 25 | 26 | import java.io.IOException; 27 | import java.util.concurrent.ExecutorService; 28 | import java.util.concurrent.Executors; 29 | 30 | import org.symphonyoss.s2.canon.example.presence.PresenceConstants; 31 | import org.symphonyoss.s2.canon.example.presence.canon.PresenceModel; 32 | import org.symphonyoss.s2.canon.example.presence.facade.Presence; 33 | import org.symphonyoss.s2.canon.example.presence.facade.PresenceJwtGenerator; 34 | import org.symphonyoss.s2.canon.runtime.ModelRegistry; 35 | import org.symphonyoss.s2.canon.runtime.ModelServlet; 36 | import org.symphonyoss.s2.canon.runtime.jjwt.JwtSubjectAuthenticator; 37 | import org.symphonyoss.s2.fugue.FugueServer; 38 | import org.symphonyoss.s2.fugue.core.trace.log.LoggerTraceContextTransactionFactory; 39 | 40 | public class PresenceServer extends FugueServer 41 | { 42 | 43 | 44 | public PresenceServer() 45 | { 46 | super("PresenceServer", PresenceConstants.SERVER_PORT); 47 | } 48 | 49 | 50 | public static void main(String[] argv) throws IOException 51 | { 52 | PresenceServer server = new PresenceServer(); 53 | Presence model = new Presence(); 54 | ExecutorService executor = Executors.newFixedThreadPool(50); 55 | PresenceJwtGenerator generator = new PresenceJwtGenerator(); 56 | JwtSubjectAuthenticator authenticator = new JwtSubjectAuthenticator(generator.getKey(), 3600000L, "unknown", generator.getSignatureAlgorithm().toString()); 57 | 58 | ModelServlet servlet = new ModelServlet(new LoggerTraceContextTransactionFactory(), new ModelRegistry().withFactories(PresenceModel.FACTORIES)) 59 | .withHandler(new UsersUserIdHandler(model, authenticator)) 60 | .withHandler(new UsersUserIdTestHandler(model, authenticator)) 61 | .withHandler(new UsersAsyncHandler(model, executor, executor, authenticator)) 62 | .withHandler(new UsersFetchHandler(model, authenticator)) 63 | // .withHandler(new UsersFetchAsyncHandler(model, executor, executor, authenticator)) 64 | // .withHandler(new UsersUpdateHandler(model, authenticator)) 65 | .withHandler(new UsersUpdateAsyncHandler(model, executor, executor, authenticator)) 66 | ; 67 | 68 | server.withComponents(model, servlet) 69 | .start(); 70 | 71 | try 72 | { 73 | server.join(); 74 | } 75 | catch (InterruptedException e) 76 | { 77 | // TODO Auto-generated catch block 78 | e.printStackTrace(); 79 | } 80 | // System.out.println("Server started, press RETURN to terminate"); 81 | // System.in.read(); 82 | // 83 | // System.out.println("Stopping..."); 84 | // 85 | // server.stop(); 86 | // 87 | // System.out.println("Finished."); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /presence-client/src/main/java/org/symphonyoss/s2/canon/example/presence/PutUsers4.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * Copyright 2018 Symphony Communication Services, LLC. 5 | * 6 | * Licensed to The Symphony Software Foundation (SSF) under one 7 | * or more contributor license agreements. See the NOTICE file 8 | * distributed with this work for additional information 9 | * regarding copyright ownership. The ASF licenses this file 10 | * to you under the Apache License, Version 2.0 (the 11 | * "License"); you may not use this file except in compliance 12 | * with the License. You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, 17 | * software distributed under the License is distributed on an 18 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19 | * KIND, either express or implied. See the License for the 20 | * specific language governing permissions and limitations 21 | * under the License. 22 | */ 23 | 24 | package org.symphonyoss.s2.canon.example.presence; 25 | 26 | import java.io.IOException; 27 | 28 | import org.apache.http.impl.client.BasicCookieStore; 29 | import org.apache.http.impl.client.CloseableHttpClient; 30 | import org.apache.http.impl.client.HttpClients; 31 | import org.slf4j.Logger; 32 | import org.slf4j.LoggerFactory; 33 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresenceInfo; 34 | import org.symphonyoss.s2.canon.example.presence.canon.PresenceHttpModelClient; 35 | import org.symphonyoss.s2.canon.example.presence.canon.PresenceModel; 36 | import org.symphonyoss.s2.canon.example.presence.canon.PresenceStatus; 37 | import org.symphonyoss.s2.canon.example.presence.canon.UserId; 38 | import org.symphonyoss.s2.canon.example.presence.canon.UserPresenceInfo; 39 | import org.symphonyoss.s2.canon.example.presence.canon.UsersUserIdPutHttpRequest; 40 | import org.symphonyoss.s2.canon.example.presence.facade.PresenceJwtGenerator; 41 | import org.symphonyoss.s2.canon.runtime.IModelRegistry; 42 | import org.symphonyoss.s2.canon.runtime.ModelRegistry; 43 | 44 | /** 45 | * Create user 4 from hard coded values using the REST endpoint. 46 | * 47 | * @author Bruce Skingle 48 | * 49 | */ 50 | public class PutUsers4 51 | { 52 | private static final Logger log_ = LoggerFactory.getLogger(PutUsers4.class); 53 | 54 | /** 55 | * Main. 56 | * 57 | * @param argv Command line args - ignored. 58 | * 59 | * @throws Exception If something goes wrong. This is just an example. 60 | */ 61 | public static void main(String[] argv) throws Exception 62 | { 63 | IModelRegistry registry = new ModelRegistry().withFactories(PresenceModel.FACTORIES); 64 | PresenceHttpModelClient client = new PresenceHttpModelClient(registry, PresenceConstants.SERVER_URL, null, new PresenceJwtGenerator()); 65 | 66 | IUserPresenceInfo japiPayload = new UserPresenceInfo.Builder() 67 | .withStatus(PresenceStatus.DoNotDisturb) 68 | .withText("I am on the phone") 69 | .build(); 70 | 71 | UsersUserIdPutHttpRequest request = client.newUsersUserIdPutHttpRequestBuilder() 72 | .withUserId(UserId.newBuilder().build(4L)) 73 | .withCanonPayload(japiPayload) 74 | .build(); 75 | 76 | BasicCookieStore cookieStore = new BasicCookieStore(); 77 | CloseableHttpClient httpclient = HttpClients.custom() 78 | .setDefaultCookieStore(cookieStore) 79 | .build(); 80 | try { 81 | request.execute(httpclient); 82 | 83 | System.err.printf("Done\n"); 84 | } 85 | finally 86 | { 87 | try 88 | { 89 | httpclient.close(); 90 | } 91 | catch (IOException e) 92 | { 93 | log_.error("Unable to close httpClient", e); 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /presence-client/src/main/java/org/symphonyoss/s2/canon/example/presence/GetUsers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * 4 | * Copyright 2018 Symphony Communication Services, LLC. 5 | * 6 | * Licensed to The Symphony Software Foundation (SSF) under one 7 | * or more contributor license agreements. See the NOTICE file 8 | * distributed with this work for additional information 9 | * regarding copyright ownership. The ASF licenses this file 10 | * to you under the Apache License, Version 2.0 (the 11 | * "License"); you may not use this file except in compliance 12 | * with the License. You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, 17 | * software distributed under the License is distributed on an 18 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19 | * KIND, either express or implied. See the License for the 20 | * specific language governing permissions and limitations 21 | * under the License. 22 | */ 23 | 24 | package org.symphonyoss.s2.canon.example.presence; 25 | 26 | import java.io.IOException; 27 | 28 | import org.apache.http.impl.client.BasicCookieStore; 29 | import org.apache.http.impl.client.CloseableHttpClient; 30 | import org.apache.http.impl.client.HttpClients; 31 | import org.slf4j.Logger; 32 | import org.slf4j.LoggerFactory; 33 | import org.symphonyoss.s2.canon.example.presence.canon.Cursor; 34 | import org.symphonyoss.s2.canon.example.presence.canon.CursorLimit; 35 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresence; 36 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresencePage; 37 | import org.symphonyoss.s2.canon.example.presence.canon.PresenceHttpModelClient; 38 | import org.symphonyoss.s2.canon.example.presence.canon.PresenceModel; 39 | import org.symphonyoss.s2.canon.example.presence.canon.UsersGetHttpRequest; 40 | import org.symphonyoss.s2.canon.example.presence.facade.PresenceJwtGenerator; 41 | import org.symphonyoss.s2.canon.runtime.IModelRegistry; 42 | import org.symphonyoss.s2.canon.runtime.ModelRegistry; 43 | import org.symphonyoss.s2.common.immutable.ImmutableByteArray; 44 | 45 | /** 46 | * Fetch all users by calling the REST endpoint. 47 | * 48 | * @author Bruce Skingle 49 | * 50 | */ 51 | public class GetUsers 52 | { 53 | private static final Logger log_ = LoggerFactory.getLogger(GetUsers.class); 54 | 55 | /** 56 | * Main. 57 | * 58 | * @param argv Command line args - ignored. 59 | * 60 | * @throws Exception If something goes wrong. This is just an example. 61 | */ 62 | public static void main(String[] argv) throws Exception 63 | { 64 | IModelRegistry registry = new ModelRegistry().withFactories(PresenceModel.FACTORIES); 65 | PresenceHttpModelClient client = new PresenceHttpModelClient(registry, PresenceConstants.SERVER_URL, null, new PresenceJwtGenerator()); 66 | 67 | UsersGetHttpRequest request = client.newUsersGetHttpRequestBuilder() 68 | .withCursor(Cursor.newBuilder().build(ImmutableByteArray.newInstance("Hello".getBytes()))) 69 | .withLimit(CursorLimit.newBuilder().build(20)) 70 | .build(); 71 | 72 | BasicCookieStore cookieStore = new BasicCookieStore(); 73 | CloseableHttpClient httpclient = HttpClients.custom() 74 | .setDefaultCookieStore(cookieStore) 75 | .build(); 76 | try { 77 | IUserPresencePage result = request.execute(httpclient); 78 | 79 | for(IUserPresence p : result.getData()) 80 | { 81 | System.err.printf("%10d %-20s %s%n", p.getUserId().getValue(), p.getStatus(), p.getText()); 82 | } 83 | } 84 | finally 85 | { 86 | try 87 | { 88 | httpclient.close(); 89 | } 90 | catch (IOException e) 91 | { 92 | log_.error("Unable to close httpClient", e); 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /presence-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | 25 | 4.0.0 26 | 27 | org.symphonyoss.s2.canon.example 28 | canon-example 29 | 0.2.1-SNAPSHOT 30 | 31 | presence-client 32 | 33 | 34 | 35 | 36 | 37 | org.symphonyoss.s2.fugue 38 | fugue-core 39 | 40 | 41 | org.symphonyoss.s2.canon 42 | canon-template-java 43 | 44 | 45 | 46 | org.symphonyoss.s2.canon 47 | canon-runtime-java 48 | 49 | 50 | org.symphonyoss.s2.canon 51 | canon-jjwt 52 | 53 | 54 | 55 | ch.qos.logback 56 | logback-classic 57 | 58 | 59 | 60 | junit 61 | junit 62 | test 63 | 64 | 65 | 66 | 67 | 68 | 69 | org.symphonyoss.s2.canon 70 | canon-maven-plugin 71 | ${canon.version} 72 | 73 | 74 | generate-sources 75 | 76 | generate-sources 77 | 78 | 79 | src/main 80 | 81 | 82 | 83 | ${canon.template.groupid} 84 | ${canon.template.java} 85 | ${canon.template.version} 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | org.codehaus.mojo 95 | build-helper-maven-plugin 96 | 97 | 98 | add-source 99 | generate-sources 100 | 101 | add-source 102 | 103 | 104 | 105 | target/generated-sources/java 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /presence-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | 25 | 4.0.0 26 | 27 | org.symphonyoss.s2.canon.example 28 | canon-example 29 | 0.2.1-SNAPSHOT 30 | 31 | presence-server 32 | 33 | 34 | 35 | ${project.groupId} 36 | presence-client 37 | ${project.version} 38 | 39 | 40 | 41 | org.symphonyoss.s2.canon 42 | canon-template-java 43 | 44 | 45 | 46 | org.symphonyoss.s2.canon 47 | canon-runtime-java 48 | 49 | 50 | org.symphonyoss.s2.canon 51 | canon-jjwt 52 | 53 | 54 | 55 | org.symphonyoss.s2.fugue 56 | fugue-core 57 | 58 | 59 | 60 | org.symphonyoss.s2.common 61 | S2-common-http 62 | 63 | 64 | 65 | ch.qos.logback 66 | logback-classic 67 | 68 | 69 | 70 | junit 71 | junit 72 | test 73 | 74 | 75 | 76 | 77 | 78 | 79 | io.fabric8 80 | docker-maven-plugin 81 | 82 | 83 | 84 | gcr.io/${gcp.project}/presence-server:${project.version} 85 | presence-server 86 | 87 | openjdk:latest 88 | 89 | artifact-with-dependencies 90 | 91 | java -cp "maven/*" com.symphony.s2.presence.PresenceServer 92 | 93 | 94 | 95 | 8080:8080 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | docker:build 104 | package 105 | 106 | build 107 | 108 | 109 | true 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /presence-client/src/main/java/org/symphonyoss/s2/canon/example/presence/facade/Presence.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2018 Symphony Communication Services, LLC. 3 | * 4 | * Licensed to The Symphony Software Foundation (SSF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | * 21 | *---------------------------------------------------------------------------------------------------- 22 | * Proforma generated from 23 | * Template groupId org.symphonyoss.s2.japigen 24 | * artifactId canon-template-java 25 | * Template name proforma/java/Model/_.java.ftl 26 | * Template version 1.0 27 | * At 2018-01-14 16:40:50 GMT-08:00 28 | *---------------------------------------------------------------------------------------------------- 29 | */ 30 | 31 | package org.symphonyoss.s2.canon.example.presence.facade; 32 | 33 | 34 | import java.util.Collection; 35 | import java.util.TreeMap; 36 | 37 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresence; 38 | import org.symphonyoss.s2.canon.example.presence.canon.IUserPresenceInfo; 39 | import org.symphonyoss.s2.canon.example.presence.canon.PresenceStatus; 40 | import org.symphonyoss.s2.canon.example.presence.canon.UserId; 41 | import org.symphonyoss.s2.canon.example.presence.canon.UserPresence; 42 | import org.symphonyoss.s2.canon.example.presence.canon.UserPresenceEntity.Builder; 43 | import org.symphonyoss.s2.canon.runtime.exception.ServerErrorException; 44 | import org.symphonyoss.s2.fugue.IFugueComponent; 45 | 46 | public class Presence implements IPresence, IFugueComponent 47 | { 48 | private TreeMap presenceMap_ = new TreeMap<>(); 49 | 50 | @Override 51 | public synchronized Collection getAllUsers() 52 | { 53 | return presenceMap_.values(); 54 | } 55 | 56 | @Override 57 | public synchronized IUserPresence getUser(UserId userId) 58 | { 59 | return presenceMap_.get(userId); 60 | } 61 | 62 | @Override 63 | public synchronized void setUser(UserId userId, IUserPresenceInfo userPresenceInfo) throws ServerErrorException 64 | { 65 | presenceMap_.put(userId, new UserPresence.Builder() 66 | .withUserId(userId) 67 | .withStatus(userPresenceInfo.getStatus()) 68 | .withText(userPresenceInfo.getText()) 69 | .build()); 70 | } 71 | 72 | @Override 73 | public void start() 74 | { 75 | /* Load presence data for known users */ 76 | 77 | Builder presenceBuilder = new UserPresence.Builder(); 78 | UserId userId; 79 | 80 | userId = UserId.newBuilder().build((long) 1); 81 | 82 | presenceBuilder.withUserId(userId); 83 | presenceBuilder.withStatus(PresenceStatus.Available); 84 | presenceBuilder.withText("I'm Free!"); 85 | 86 | presenceMap_.put(userId, presenceBuilder.build()); 87 | 88 | userId = UserId.newBuilder().build((long) 2); 89 | 90 | presenceBuilder.withUserId(userId); 91 | presenceBuilder.withStatus(PresenceStatus.Available); 92 | presenceBuilder.withText("Talk to me!"); 93 | 94 | presenceMap_.put(userId, presenceBuilder.build()); 95 | 96 | 97 | userId = UserId.newBuilder().build((long) 3); 98 | 99 | presenceBuilder.withUserId(userId); 100 | presenceBuilder.withStatus(PresenceStatus.Busy); 101 | presenceBuilder.withText(""); 102 | 103 | presenceMap_.put(userId, presenceBuilder.build()); 104 | } 105 | 106 | @Override 107 | public void stop() 108 | { 109 | } 110 | } 111 | /*---------------------------------------------------------------------------------------------------- 112 | * End of template proforma/java/Model/_.java.ftl 113 | * End of code generation 114 | *------------------------------------------------------------------------------------------------- */ -------------------------------------------------------------------------------- /presence-client/src/main/canon/presence.json: -------------------------------------------------------------------------------- 1 | { 2 | "canon": "0.0.1", 3 | "info": { 4 | "title": "Japigen Simple RPC Test Case", 5 | "license": { 6 | "name": "Apache2" 7 | } 8 | }, 9 | "id": "org.symphonyoss.s2.canon.example.presence", 10 | "version": "0.1", 11 | "basePath": "/presence/v2", 12 | "model": { 13 | "javaGenPackage": "org.symphonyoss.s2.canon.example.presence.canon", 14 | "javaFacadePackage": "org.symphonyoss.s2.canon.example.presence.facade" 15 | }, 16 | "methods": { 17 | "/users": { 18 | "description": "Fetch all users' presence.", 19 | "parameterSets": [ 20 | "#/components/parameterSets/pagination" 21 | ], 22 | "get": { 23 | "response": { 24 | "schema": { 25 | "$ref": "#/components/schemas/UserPresencePage" 26 | } 27 | } 28 | }, 29 | "put": { 30 | "description": "A weird no payload and no response mehod." 31 | } 32 | }, 33 | "/users/{userId}": { 34 | "description": "Manipulate a single user's presence.", 35 | "parameters": { 36 | "userId": { 37 | "in": "path", 38 | "required": true, 39 | "schema": { 40 | "$ref": "#/components/schemas/UserId" 41 | } 42 | } 43 | }, 44 | "get": { 45 | "description": "Fetch a single user's presence.", 46 | "response": { 47 | "required": false, 48 | "schema": { 49 | "$ref": "#/components/schemas/UserPresence" 50 | } 51 | } 52 | }, 53 | "put": { 54 | "description": "Set a single user's presence.", 55 | "payload": { 56 | "required": true, 57 | "schema": { 58 | "$ref": "#/components/schemas/UserPresenceInfo" 59 | } 60 | } 61 | } 62 | }, 63 | "/users/{userId}/test": { 64 | "description": "Manipulate a single user's presence.", 65 | "parameters": { 66 | "userId": { 67 | "in": "path", 68 | "required": true, 69 | "schema": { 70 | "$ref": "#/components/schemas/UserId" 71 | } 72 | } 73 | }, 74 | "get": { 75 | "description": "Fetch a single user's presence.", 76 | "response": { 77 | "schema": { 78 | "$ref": "#/components/schemas/UserPresence" 79 | } 80 | } 81 | } 82 | }, 83 | "/users/update": { 84 | "description": "Manipulate a batch of users' presence.", 85 | "post": { 86 | "payload": { 87 | "required": true, 88 | "schema": { 89 | "$ref": "#/components/schemas/UserPresenceList" 90 | } 91 | } 92 | } 93 | }, 94 | "/users/fetch": { 95 | "description": "Fetch a batch of users' presence.", 96 | "post": { 97 | "payload": { 98 | "required": true, 99 | "multiple": true, 100 | "schema": { 101 | "$ref": "#/components/schemas/UserId" 102 | } 103 | }, 104 | "response": { 105 | "required": false, 106 | "multiple": true, 107 | "schema": { 108 | "$ref": "#/components/schemas/UserPresence" 109 | } 110 | } 111 | } 112 | } 113 | }, 114 | "components": { 115 | "schemas": { 116 | "UserId": { 117 | "description": "A Symphony external user ID.", 118 | "type": "integer", 119 | "format": "int64", 120 | "minimum": 0 121 | }, 122 | "Cursor": { 123 | "description": "An opaque token returned by the server to allow the next page to be requested.", 124 | "type": "string", 125 | "format": "byte" 126 | }, 127 | "CursorLimit": { 128 | "description": "A cursor limit, the max number of records to return.", 129 | "type": "integer", 130 | "format": "int32", 131 | "minimum": 0, 132 | "maximum": 50 133 | }, 134 | "CursorInfo": { 135 | "description": "Links to the next and prev pages.", 136 | "type": "object", 137 | 138 | "properties": { 139 | "previous": { 140 | "$ref": "#/components/schemas/Cursor" 141 | }, 142 | "next": { 143 | "$ref": "#/components/schemas/Cursor" 144 | } 145 | } 146 | }, 147 | "PresenceStatus": { 148 | "description": "A presence status.", 149 | "type": "string", 150 | "enum": [ 151 | "Offline", 152 | "Available", 153 | "Busy", 154 | "DoNotDisturb", 155 | "OnThePhone" 156 | ] 157 | }, 158 | "UserPresenceInfo": { 159 | "type": "object", 160 | "properties": { 161 | "status": { 162 | "$ref": "#/components/schemas/PresenceStatus" 163 | }, 164 | "text": { 165 | "description": "A short message set by the user.", 166 | "type": "string" 167 | } 168 | } 169 | }, 170 | "UserPresence": { 171 | "type": "object", 172 | "properties": { 173 | "userId": { 174 | "$ref": "#/components/schemas/UserId" 175 | }, 176 | "status": { 177 | "$ref": "#/components/schemas/PresenceStatus" 178 | }, 179 | "text": { 180 | "description": "A short message set by the user.", 181 | "type": "string" 182 | } 183 | } 184 | }, 185 | "UserPresenceList": { 186 | "type": "object", 187 | "properties": { 188 | "data": { 189 | "description": "A list of user status records.", 190 | "type": "array", 191 | "x-canon-cardinality": "LIST", 192 | "items": { 193 | "$ref": "#/components/schemas/UserPresence" 194 | } 195 | } 196 | } 197 | }, 198 | "UserPresencePage": { 199 | "type": "object", 200 | "properties": { 201 | "data": { 202 | "description": "A list of user status records.", 203 | "type": "array", 204 | "x-canon-cardinality": "LIST", 205 | "items": { 206 | "$ref": "#/components/schemas/UserPresence" 207 | } 208 | }, 209 | "cursors": { 210 | "$ref": "#/components/schemas/CursorInfo" 211 | } 212 | } 213 | } 214 | }, 215 | "parameterSets": { 216 | "pagination": { 217 | "cursor": { 218 | "description": "Cursor position", 219 | "in": "query", 220 | "required": false, 221 | "schema": { 222 | "$ref": "#/components/schemas/Cursor" 223 | } 224 | }, 225 | "limit": { 226 | "description": "max records to return", 227 | "in": "query", 228 | "required": false, 229 | "schema": { 230 | "$ref": "#/components/schemas/CursorLimit" 231 | } 232 | } 233 | } 234 | } 235 | } 236 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | 4.0.0 17 | 18 | 19 | org.symphonyoss.s2 20 | S2-super-pom 21 | 0.2.4 22 | 23 | 24 | org.symphonyoss.s2.canon.example 25 | canon-example 26 | 0.2.1-SNAPSHOT 27 | JSON API Generation Tooling Example Application 28 | https://github.com/symphonyoss/canon-example 29 | pom 30 | 31 | 32 | presence-client 33 | presence-server 34 | 35 | 36 | 37 | 38 | Apache License, Version 2.0 39 | https://www.apache.org/licenses/LICENSE-2.0.txt 40 | 41 | 42 | 43 | 44 | scm:git:git://github.com/symphonyoss/canon-example.git 45 | scm:git:git@github.com:symphonyoss/canon-example.git 46 | https://github.com/symphonyoss/canon-example 47 | canon-example-0.0.1 48 | 49 | 50 | 51 | 52 | bruceskingle 53 | Bruce Skingle 54 | bruce.skingle@symphony.com 55 | http://github.com/bruceskingle 56 | Symphony Communication Services LLC 57 | http://symphony.com 58 | 59 | Chief Architect 60 | 61 | 62 | 63 | 64 | 65 | UTF-8 66 | 1.8 67 | 1.8 68 | 0.2.8 69 | 0.2.22 70 | org.symphonyoss.s2.canon 71 | canon-template-java 72 | ${canon.version} 73 | 74 | 0.2.53 75 | sym-dev-arch 76 | 77 | 78 | 79 | 80 | sonatype-oss-public 81 | https://oss.sonatype.org/content/groups/public/ 82 | 83 | true 84 | 85 | 86 | true 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | org.symphonyoss.s2.common 95 | S2-common-core 96 | ${s2.common.version} 97 | 98 | 99 | org.symphonyoss.s2.common 100 | S2-common-http 101 | ${s2.common.version} 102 | 103 | 104 | org.symphonyoss.s2.common 105 | S2-common-dom 106 | ${s2.common.version} 107 | 108 | 109 | org.symphonyoss.s2.common 110 | S2-common-dom-jackson 111 | ${s2.common.version} 112 | 113 | 114 | 115 | org.symphonyoss.s2.canon 116 | canon-template-java 117 | ${canon.template.version} 118 | 119 | 120 | 121 | org.symphonyoss.s2.canon 122 | canon-runtime-java 123 | ${canon.version} 124 | 125 | 126 | org.symphonyoss.s2.canon 127 | canon-jjwt 128 | ${canon.version} 129 | 130 | 131 | 132 | 133 | org.symphonyoss.s2.fugue 134 | fugue-core 135 | ${fugue.version} 136 | 137 | 138 | 139 | com.google.code.findbugs 140 | jsr305 141 | 3.0.2 142 | 143 | 144 | 145 | ch.qos.logback 146 | logback-classic 147 | 1.0.13 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | org.slf4j 157 | slf4j-api 158 | 159 | 160 | 161 | 162 | 163 | 164 | io.fabric8 165 | docker-maven-plugin 166 | 0.23.0 167 | 168 | 170 | 171 | org.eclipse.m2e 172 | lifecycle-mapping 173 | 1.0.0 174 | 175 | 176 | 177 | 178 | 179 | 180 | org.symphonyoss.s2.canon 181 | 182 | 183 | canon-maven-plugin 184 | 185 | 186 | [0.0.1-SNAPSHOT,) 187 | 188 | 189 | 190 | generate-sources 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # canon-example 2 | An example service based on japigen code generation 3 | 4 | In order to follow these instructions all the way through you will need access to a Google Cloud project, which your tech lead should be able to give you. If you do not have access to Google Cloud and wish to follow the local parts of these instructions then use the default name **sym-dev-arch** where a project name is required. 5 | 6 | Point your web browser to the [Google Cloud Platform Console](https://console.cloud.google.com), look near the top left corner of the page for the project selector, the project name shown in this screen shot is **sym-dev-arch**. 7 | 8 | ![GCP Project](./GCP1.png) 9 | 10 | If the correct project is not listed then talk to your project lead to have yourself added to the project. 11 | 12 | If the name of the project is globally unique (as it is in the screen shot) then the project ID will be the same as the project name, if not then the project ID will have additional digits added to the name to make it unique. The Project ID is shown in the dashboard section of the GCP Console as shown in the screen shot above. Make a note of the Project ID. 13 | 14 | In order to build the sample application you will need a local Docker container. If you do not have a Docker container installed then you can download the Community Edition from [The Docker Store](https://www.docker.com/community-edition). 15 | 16 | ## Clone the Repo and Set Environment Variables 17 | Clone this repo into a convenient location: 18 | 19 | ``` 20 | $ mkdir /tmp/git 21 | $ cd /tmp/git 22 | $ git clone https://github.com/SymphonyOSF/canon-example.git 23 | Cloning into 'canon-example'... 24 | remote: Counting objects: 118, done. 25 | remote: Compressing objects: 100% (57/57), done. 26 | remote: Total 118 (delta 45), reused 91 (delta 22), pack-reused 0 27 | Receiving objects: 100% (118/118), 33.69 KiB | 11.23 MiB/s, done. 28 | Resolving deltas: 100% (45/45), done. 29 | $ cd canon-example/ 30 | $ ls 31 | LICENSE README.md S2-presence-client S2-presence-server pom.xml 32 | $ 33 | ``` 34 | 35 | Set the ID of the project you will be using as the variable **$PROJECT** with the following commands **N.B. replace the name "sym-dev-arch" with the ID of the project you will be using** 36 | 37 | ``` 38 | $ export PROJECT=sym-dev-arch 39 | $ echo $PROJECT 40 | sym-dev-arch 41 | $ 42 | ``` 43 | 44 | Edit the project pom (the file pom.xml in the current directory), search for the definition of the 45 | property **gcp.project** and replace the name **sym-dev-arch** with the name of your Google Cloud project. 46 | 47 | ``` 48 | sym-dev-arch 49 | 50 | ``` 51 | 52 | Set the variable **$VERSION** to the current version for this project, you can do this with the following command: 53 | 54 | ``` 55 | $ export VERSION=`mvn help:evaluate -Dexpression=project.version | grep -v "^[[]"` 56 | $ echo $VERSION 57 | 0.0.1-SNAPSHOT 58 | $ 59 | ``` 60 | 61 | ## Build and Run the PresenceServer locally 62 | Build the application by executing the command: 63 | 64 | ``` 65 | $ mvn clean package 66 | [INFO] Scanning for projects... 67 | [INFO] ------------------------------------------------------------------------ 68 | [INFO] Reactor Build Order: 69 | [INFO] 70 | [INFO] JAPIgen Example Application 71 | [INFO] S2-presence-client 72 | [INFO] S2-presence-server 73 | [INFO] 74 | [INFO] ------------------------------------------------------------------------ 75 | [INFO] Building JAPIgen Example Application 0.0.1-SNAPSHOT 76 | [INFO] ------------------------------------------------------------------------ 77 | ``` 78 | _Many lines of output omitted_ 79 | 80 | ``` 81 | [INFO] --- maven-jar-plugin:3.0.1:jar (default-jar) @ S2-presence-server --- 82 | [INFO] Building jar: /Users/bruce/symphony/git-SymphonyOSF/canon-example/S2-presence-server/target/S2-presence-server-0.0.1-SNAPSHOT.jar 83 | [INFO] 84 | [INFO] --- docker-maven-plugin:0.23.0:build (docker:build) @ S2-presence-server --- 85 | [INFO] Copying files to /Users/bruce/symphony/git-SymphonyOSF/canon-example/S2-presence-server/target/docker/presence-server/0.0.1-SNAPSHOT/build/maven 86 | [INFO] Building tar: /Users/bruce/symphony/git-SymphonyOSF/canon-example/S2-presence-server/target/docker/presence-server/0.0.1-SNAPSHOT/tmp/docker-build.tar 87 | [INFO] DOCKER> [presence-server:0.0.1-SNAPSHOT] "presence-server": Created docker-build.tar in 557 milliseconds 88 | [INFO] DOCKER> [presence-server:0.0.1-SNAPSHOT] "presence-server": Built image sha256:00261 89 | [INFO] DOCKER> [presence-server:0.0.1-SNAPSHOT] "presence-server": Removed old image sha256:3a02b 90 | [INFO] ------------------------------------------------------------------------ 91 | [INFO] Reactor Summary: 92 | [INFO] 93 | [INFO] JAPIgen Example Application ........................ SUCCESS [ 0.581 s] 94 | [INFO] S2-presence-client ................................. SUCCESS [ 3.568 s] 95 | [INFO] S2-presence-server ................................. SUCCESS [ 2.808 s] 96 | [INFO] ------------------------------------------------------------------------ 97 | [INFO] BUILD SUCCESS 98 | [INFO] ------------------------------------------------------------------------ 99 | [INFO] Total time: 7.139 s 100 | [INFO] Finished at: 2018-01-23T13:48:50-08:00 101 | [INFO] Final Memory: 36M/754M 102 | [INFO] ------------------------------------------------------------------------ 103 | $ 104 | ``` 105 | 106 | The build generates a docker image for the server process including all the dependencies. We can execute the process directly with the following command: 107 | 108 | ``` 109 | $ java -cp "S2-presence-server/target/docker/gcr.io/$PROJECT/presence-server/$VERSION/build/maven/*" com.symphony.s2.presence.PresenceServer 110 | 111 | ``` 112 | 113 | This starts a server which listens for HTTP requests on port 8080, you will see a large number of log messages on stdout. You can test the server from another terminal window with the following command: 114 | 115 | ``` 116 | $ curl http://127.0.0.1:8080/presence/v2/users 117 | {"_type":"https://github.com/bruceskingle/canon/blob/master/canon-test/src/main/resources/test/presence.json#/components/schemas/UserPresencePage","data":[{"_type":"https://github.com/bruceskingle/canon/blob/master/canon-test/src/main/resources/test/presence.json#/components/schemas/UserPresence","status":"Available","text":"I'm Free!","userId":1},{"_type":"https://github.com/bruceskingle/canon/blob/master/canon-test/src/main/resources/test/presence.json#/components/schemas/UserPresence","status":"Available","text":"Talk to me!","userId":2},{"_type":"https://github.com/bruceskingle/canon/blob/master/canon-test/src/main/resources/test/presence.json#/components/schemas/UserPresence","status":"Busy","text":"","userId":3}]} 118 | $ 119 | ``` 120 | 121 | The GET /presence/v2/users method returns a list of the presence satus for all users in the system. The example implementation initializes its data set with three users, note that the data array in the response contains the status for users with userId 1, 2, and 3 and the response ends **"userId":3}]}** 122 | 123 | Kill the locally running server by typing Ctrl-C in the window where you started it. 124 | 125 | ## Deploy to Your Local Docker Container 126 | You can see what containers are running with the command 127 | 128 | ``` 129 | $ docker ps 130 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 131 | $ 132 | ``` 133 | 134 | You can start a local copy of the application with the command: 135 | 136 | ``` 137 | $ mvn docker:start 138 | [INFO] Scanning for projects... 139 | [INFO] ------------------------------------------------------------------------ 140 | [INFO] Reactor Build Order: 141 | [INFO] 142 | [INFO] JAPIgen Example Application 143 | [INFO] S2-presence-client 144 | [INFO] S2-presence-server 145 | [INFO] 146 | [INFO] ------------------------------------------------------------------------ 147 | [INFO] Building JAPIgen Example Application 0.0.1-SNAPSHOT 148 | [INFO] ------------------------------------------------------------------------ 149 | [INFO] 150 | [INFO] --- docker-maven-plugin:0.23.0:start (default-cli) @ canon-example --- 151 | [INFO] 152 | [INFO] ------------------------------------------------------------------------ 153 | [INFO] Building S2-presence-client 0.0.1-SNAPSHOT 154 | [INFO] ------------------------------------------------------------------------ 155 | [INFO] 156 | [INFO] --- docker-maven-plugin:0.23.0:start (default-cli) @ S2-presence-client --- 157 | [INFO] 158 | [INFO] ------------------------------------------------------------------------ 159 | [INFO] Building S2-presence-server 0.0.1-SNAPSHOT 160 | [INFO] ------------------------------------------------------------------------ 161 | [INFO] 162 | [INFO] --- docker-maven-plugin:0.23.0:start (default-cli) @ S2-presence-server --- 163 | [INFO] DOCKER> [gcr.io/sym-dev-arch/presence-server:0.0.1-SNAPSHOT] "presence-server": Start container c38211433373 164 | [INFO] ------------------------------------------------------------------------ 165 | [INFO] Reactor Summary: 166 | [INFO] 167 | [INFO] JAPIgen Example Application ........................ SUCCESS [ 0.939 s] 168 | [INFO] S2-presence-client ................................. SUCCESS [ 0.021 s] 169 | [INFO] S2-presence-server ................................. SUCCESS [ 0.628 s] 170 | [INFO] ------------------------------------------------------------------------ 171 | [INFO] BUILD SUCCESS 172 | [INFO] ------------------------------------------------------------------------ 173 | [INFO] Total time: 2.125 s 174 | [INFO] Finished at: 2018-01-23T15:39:54-08:00 175 | [INFO] Final Memory: 25M/411M 176 | [INFO] ------------------------------------------------------------------------ 177 | $ docker ps 178 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 179 | c38211433373 gcr.io/sym-dev-arch/presence-server:0.0.1-SNAPSHOT "/bin/sh -c 'java -c…" 1 second ago Up 4 seconds 0.0.0.0:8080->8080/tcp epic_snyder 180 | $ 181 | ``` 182 | 183 | As you can see from the **docker ps** output, port 8080 in the container is mapped to the same port on the host machine, so you can use the same command as before to check that the server is running: 184 | 185 | ``` 186 | $ curl http://127.0.0.1:8080/presence/v2/users 187 | {"_type":"https://github.com/bruceskingle/canon/blob/master/canon-test/src/main/resources/test/presence.json#/components/schemas/UserPresencePage","data":[{"_type":"https://github.com/bruceskingle/canon/blob/master/canon-test/src/main/resources/test/presence.json#/components/schemas/UserPresence","status":"Available","text":"I'm Free!","userId":1},{"_type":"https://github.com/bruceskingle/canon/blob/master/canon-test/src/main/resources/test/presence.json#/components/schemas/UserPresence","status":"Available","text":"Talk to me!","userId":2},{"_type":"https://github.com/bruceskingle/canon/blob/master/canon-test/src/main/resources/test/presence.json#/components/schemas/UserPresence","status":"Busy","text":"","userId":3}]} 188 | $ 189 | ``` 190 | 191 | To stop the container you can use the command: 192 | 193 | ``` 194 | $ mvn docker:stop 195 | [INFO] Scanning for projects... 196 | [INFO] ------------------------------------------------------------------------ 197 | [INFO] Reactor Build Order: 198 | [INFO] 199 | [INFO] JAPIgen Example Application 200 | [INFO] S2-presence-client 201 | [INFO] S2-presence-server 202 | [INFO] 203 | [INFO] ------------------------------------------------------------------------ 204 | [INFO] Building JAPIgen Example Application 0.0.1-SNAPSHOT 205 | [INFO] ------------------------------------------------------------------------ 206 | [INFO] 207 | [INFO] --- docker-maven-plugin:0.23.0:stop (default-cli) @ canon-example --- 208 | [INFO] 209 | [INFO] ------------------------------------------------------------------------ 210 | [INFO] Building S2-presence-client 0.0.1-SNAPSHOT 211 | [INFO] ------------------------------------------------------------------------ 212 | [INFO] 213 | [INFO] --- docker-maven-plugin:0.23.0:stop (default-cli) @ S2-presence-client --- 214 | [INFO] 215 | [INFO] ------------------------------------------------------------------------ 216 | [INFO] Building S2-presence-server 0.0.1-SNAPSHOT 217 | [INFO] ------------------------------------------------------------------------ 218 | [INFO] 219 | [INFO] --- docker-maven-plugin:0.23.0:stop (default-cli) @ S2-presence-server --- 220 | [INFO] DOCKER> [gcr.io/sym-dev-arch/presence-server:0.0.1-SNAPSHOT] "presence-server": Stop and removed container c38211433373 after 0 ms 221 | [INFO] ------------------------------------------------------------------------ 222 | [INFO] Reactor Summary: 223 | [INFO] 224 | [INFO] JAPIgen Example Application ........................ SUCCESS [ 0.936 s] 225 | [INFO] S2-presence-client ................................. SUCCESS [ 0.019 s] 226 | [INFO] S2-presence-server ................................. SUCCESS [ 10.615 s] 227 | [INFO] ------------------------------------------------------------------------ 228 | [INFO] BUILD SUCCESS 229 | [INFO] ------------------------------------------------------------------------ 230 | [INFO] Total time: 12.088 s 231 | [INFO] Finished at: 2018-01-23T15:45:16-08:00 232 | [INFO] Final Memory: 25M/410M 233 | [INFO] ------------------------------------------------------------------------ 234 | $ 235 | 236 | ``` 237 | 238 | If you re-run docker ps you can confirm that the container was terminated: 239 | 240 | ``` 241 | $ docker ps 242 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 243 | $ 244 | ``` 245 | 246 | ## Setup Your Google Cloud Development Environment 247 | You need to be given access to the Google Project for your service, and to install the Google SDK. 248 | 249 | 250 | If you do not already have it installed, download the gcloud SDK from [https://cloud.google.com/sdk/downloads](https://cloud.google.com/sdk/downloads) 251 | 252 | Next install **kubectl** (it is safe to execute this command if it is already installed) and set values for various configuration parameters: 253 | 254 | ``` 255 | $ gcloud components install kubectl 256 | 257 | All components are up to date. 258 | $ gcloud config set project $PROJECT 259 | Updated property [core/project]. 260 | $ gcloud config set compute/region us-central1 261 | Updated property [compute/region]. 262 | $ gcloud config set compute/zone us-central1-b 263 | Updated property [compute/zone]. 264 | $ gcloud config list 265 | [compute] 266 | region = us-central1 267 | zone = us-central1-b 268 | [core] 269 | account = your.name@your.domain 270 | disable_usage_reporting = True 271 | project = sym-dev-arch 272 | 273 | Your active configuration is: [default] 274 | $ 275 | 276 | ``` 277 | 278 | ## Setup A Google Cloud Kubernetes Cluster 279 | This would normally be done once, by the tech lead, for any given service. 280 | 281 | Choose a name for the cluster and set it as $CLUSTER and then create a cluster with the following commands: 282 | 283 | ``` 284 | $ export CLUSTER=your-cluster-name 285 | $ echo $CLUSTER 286 | your-cluster-name 287 | $ gcloud container clusters create $CLUSTER 288 | Creating cluster your-cluster-name.../ 289 | $ 290 | ``` 291 | 292 | This process may take several minutes. Once it completes, verify that you have connectivity to the cluster as follows: 293 | 294 | ``` 295 | $ gcloud container clusters list 296 | NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS 297 | your-cluster-name us-central1-b 1.7.11-gke.1 130.211.131.169 n1-standard-1 1.7.11-gke.1 3 RUNNING 298 | $ gcloud container clusters get-credentials $CLUSTER 299 | Fetching cluster endpoint and auth data. 300 | kubeconfig entry generated for your-cluster-name. 301 | $ kubectl get services 302 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 303 | kubernetes ClusterIP 10.31.240.1 443/TCP 14h 304 | $ 305 | ``` 306 | 307 | Also check that you can see the cluster in the Google Cloud Console, select **Kubernetes Engine** in the left nav: 308 | 309 | ![GCP Kubernetes Engine](./GCP2.png) 310 | 311 | and then you should see the cluster, like this: 312 | 313 | ![GCP Kubernetes Cluster](./GCP3.png) 314 | 315 | 316 | You can see the generated docker image in your local docker registry by executing the command: 317 | 318 | ``` 319 | $ docker images 320 | REPOSITORY TAG IMAGE ID CREATED SIZE 321 | gcr.io/sym-dev-arch/presence-server 0.0.1-SNAPSHOT fddefc59a7f5 19 minutes ago 753MB 322 | $ 323 | ``` 324 | 325 | We now need to push this image to the Docker registry in your Google Project: 326 | 327 | ``` 328 | $ gcloud docker -- push gcr.io/$PROJECT/presence-server:$VERSION 329 | The push refers to repository [gcr.io/sym-dev-arch/presence-server] 330 | bb4a67556d99: Pushed 331 | 875b1eafb4d0: Layer already exists 332 | 7ce1a454660d: Layer already exists 333 | d3b195003fcc: Layer already exists 334 | 92bd1433d7c5: Layer already exists 335 | f0ed7f14cbd1: Layer already exists 336 | b31411566900: Layer already exists 337 | 06f4de5fefea: Layer already exists 338 | 851f3e348c69: Layer already exists 339 | e27a10675c56: Layer already exists 340 | 0.0.1-SNAPSHOT: digest: sha256:d91bfe8c5a1a8d83b62dc1d7e6182ef319fc82798268834f3a4aa12b65b3fcfa size: 2423 341 | $ 342 | 343 | ``` 344 | 345 | The image is visible in the **Container Registry** section of the GCP Console: 346 | 347 | ![GCP Docker Immages](./GCP4.png) 348 | 349 | Now we can deploy the image: 350 | 351 | ``` 352 | $ kubectl run presence-server --image gcr.io/$PROJECT/presence-server:$VERSION --port 8080 353 | deployment "presence-server" created 354 | $ 355 | ``` 356 | 357 | We can find the ID of the running instance (known as a pod in Kubernetes) like this: 358 | 359 | ``` 360 | $ kubectl get pods 361 | NAME READY STATUS RESTARTS AGE 362 | presence-server-775063857-mbqw8 1/1 Running 0 39s 363 | ``` 364 | 365 | ...and see the log output for a given pod like this: 366 | 367 | ``` 368 | $ kubectl logs presence-server-775063857-mbqw8 369 | 00:14:38.677 [main] DEBUG org.eclipse.jetty.util.log - Logging to Logger[org.eclipse.jetty.util.log] via org.eclipse.jetty.util.log.Slf4jLog 370 | ``` 371 | _Many lines of log output omitted_ 372 | 373 | ``` 374 | 00:14:39.292 [main] INFO o.e.jetty.server.AbstractConnector - Started ServerConnector@694e1548{HTTP/1.1,[http/1.1]}{0.0.0.0:8080} 375 | 00:14:39.298 [main] DEBUG o.e.j.u.component.AbstractLifeCycle - STARTED @1264ms ServerConnector@694e1548{HTTP/1.1,[http/1.1]}{0.0.0.0:8080} 376 | 00:14:39.299 [main] INFO org.eclipse.jetty.server.Server - Started @1264ms 377 | 00:14:39.299 [main] DEBUG o.e.j.u.component.AbstractLifeCycle - STARTED @1265ms org.eclipse.jetty.server.Server@7791a895[9.4.8.v20171121] 378 | ``` 379 | 380 | As we can see, the servers embedded Jetty server is listening on port 8080. 381 | Now we can expose the servers service port with the following command: 382 | 383 | ``` 384 | $ kubectl expose deployment presence-server --target-port=8080 --type=LoadBalancer 385 | service "presence-server" exposed 386 | $ kubectl get services 387 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 388 | kubernetes ClusterIP 10.31.240.1 443/TCP 21h 389 | presence-server LoadBalancer 10.31.255.10 8080:31018/TCP 2s 390 | ``` 391 | 392 | It takes some time for the load balancer to be configured, so if you don't see an EXTERNAL-IP address first time you run the get services command then just wait a minute and try again. 393 | 394 | ``` 395 | $ kubectl get services 396 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 397 | kubernetes ClusterIP 10.31.240.1 443/TCP 21h 398 | presence-server LoadBalancer 10.31.250.123 35.188.28.109 8080:31825/TCP 1m 399 | $ 400 | ``` 401 | 402 | 403 | The external IP address is shown on the last line of output above (**35.188.28.109** in this case), and we can use the same curl command to check that the server is actually working: 404 | 405 | ``` 406 | $ curl http://35.188.28.109:8080/presence/v2/users 407 | {"_type":"https://github.com/bruceskingle/canon/blob/master/canon-test/src/main/resources/test/presence.json#/components/schemas/UserPresencePage","data":[{"_type":"https://github.com/bruceskingle/canon/blob/master/canon-test/src/main/resources/test/presence.json#/components/schemas/UserPresence","status":"Available","text":"I'm Free!","userId":1},{"_type":"https://github.com/bruceskingle/canon/blob/master/canon-test/src/main/resources/test/presence.json#/components/schemas/UserPresence","status":"Available","text":"Talk to me!","userId":2},{"_type":"https://github.com/bruceskingle/canon/blob/master/canon-test/src/main/resources/test/presence.json#/components/schemas/UserPresence","status":"Busy","text":"","userId":3}]} 408 | $ 409 | ``` 410 | 411 | Note again that the response ends the response ends **"userId":3}]}**. 412 | 413 | ## Make a code change 414 | Now we will make a change to the application and re-deploy. Find the class UsersAsyncHandler.java. The method handleGet is where the business logic of the GET request we are making is implemented and the line which beging **builder.withData(** is where the presence status of all known users is added to the response. 415 | 416 | Comment out that line by inserting two slashes at the start of the line: 417 | 418 | ``` 419 | @Override 420 | public void handleGet(IConsumer _consumer, Cursor cursor, CursorLimit limit) throws JapiException 421 | { 422 | Builder builder = getModel().getUserPresencePageFactory().newBuilder(); 423 | 424 | //builder.withData(new ArrayList(getModel().getAllUsers())); 425 | 426 | _consumer.consume(builder.build()); 427 | _consumer.close(); 428 | } 429 | ``` 430 | 431 | Rebuild the application by executing the command: 432 | 433 | ``` 434 | $ mvn clean package 435 | ``` 436 | 437 | When the build is complete, push the updated Docker image: 438 | 439 | ``` 440 | $ gcloud docker -- push gcr.io/$PROJECT/presence-server:$VERSION 441 | The push refers to repository [gcr.io/sym-dev-arch/presence-server] 442 | e700695e60f6: Pushed 443 | 875b1eafb4d0: Layer already exists 444 | 7ce1a454660d: Layer already exists 445 | d3b195003fcc: Layer already exists 446 | 92bd1433d7c5: Layer already exists 447 | f0ed7f14cbd1: Layer already exists 448 | b31411566900: Layer already exists 449 | 06f4de5fefea: Layer already exists 450 | 851f3e348c69: Layer already exists 451 | e27a10675c56: Layer already exists 452 | 0.0.1-SNAPSHOT: digest: sha256:de009b313484913b60a588a3f76b385e6d9abf3532105466547471063ee183e2 size: 2423 453 | 454 | ``` 455 | 456 | The delete the currently running pod, which will force a re-deploy: 457 | 458 | ``` 459 | $ kubectl get pods 460 | NAME READY STATUS RESTARTS AGE 461 | presence-server-775063857-3gk4b 1/1 Running 0 10m 462 | $ kubectl delete pod presence-server-775063857-3gk4b 463 | pod "presence-server-775063857-3gk4b" deleted 464 | $ 465 | 466 | ``` 467 | 468 | An immediate get pods will show the old pod being terminated and a new one being created: 469 | 470 | ``` 471 | $ kubectl get pods 472 | NAME READY STATUS RESTARTS AGE 473 | presence-server-775063857-2wn04 0/1 ContainerCreating 0 5s 474 | presence-server-775063857-3gk4b 1/1 Terminating 0 11m 475 | $ 476 | 477 | ``` 478 | 479 | Once the new pod has started, re-run the curl command: 480 | 481 | ``` 482 | 483 | $ kubectl get pods 484 | NAME READY STATUS RESTARTS AGE 485 | presence-server-775063857-2wn04 1/1 Running 0 56s 486 | $ curl http://35.202.182.219:8080/presence/v2/users 487 | {"_type":"https://github.com/bruceskingle/canon/blob/master/canon-test/src/main/resources/test/presence.json#/components/schemas/UserPresencePage","data":[]} 488 | $ 489 | 490 | ``` 491 | 492 | Note that the response now contains no UserPresence objects and now ends ** "data":[]}** 493 | 494 | 495 | --------------------------------------------------------------------------------