From b997060a022626e88505b12d74117050b9717209 Mon Sep 17 00:00:00 2001 From: "zhong.zhou" Date: Thu, 22 Jan 2026 11:56:04 +0800 Subject: [PATCH] Hello world --- conf/serviceConfig/helloworld.xml | 13 +++ conf/springConfigXml/helloworld.xml | 27 ++++++ conf/zstack.xml | 1 + plugin/helloworld/pom.xml | 77 +++++++++++++++ .../example/APICreateGreetingEvent.java | 24 +++++ .../plugin/example/APICreateGreetingMsg.java | 21 +++++ .../example/APIDeleteGreetingEvent.java | 14 +++ .../plugin/example/APIDeleteGreetingMsg.java | 23 +++++ .../plugin/example/APIHelloWorldEvent.java | 24 +++++ .../plugin/example/APIHelloWorldMsg.java | 20 ++++ .../org/zstack/plugin/example/Greeting.java | 7 ++ .../zstack/plugin/example/GreetingBase.java | 50 ++++++++++ .../plugin/example/GreetingInventory.java | 61 ++++++++++++ .../plugin/example/GreetingMessage.java | 5 + .../org/zstack/plugin/example/GreetingVO.java | 51 ++++++++++ .../zstack/plugin/example/GreetingVO_.java | 14 +++ .../example/HelloWorldApiInterceptor.java | 23 +++++ .../plugin/example/HelloWorldManager.java | 5 + .../plugin/example/HelloWorldManagerImpl.java | 93 +++++++++++++++++++ 19 files changed, 553 insertions(+) create mode 100644 conf/serviceConfig/helloworld.xml create mode 100644 conf/springConfigXml/helloworld.xml create mode 100755 plugin/helloworld/pom.xml create mode 100755 plugin/helloworld/src/main/java/org/zstack/plugin/example/APICreateGreetingEvent.java create mode 100755 plugin/helloworld/src/main/java/org/zstack/plugin/example/APICreateGreetingMsg.java create mode 100755 plugin/helloworld/src/main/java/org/zstack/plugin/example/APIDeleteGreetingEvent.java create mode 100755 plugin/helloworld/src/main/java/org/zstack/plugin/example/APIDeleteGreetingMsg.java create mode 100755 plugin/helloworld/src/main/java/org/zstack/plugin/example/APIHelloWorldEvent.java create mode 100755 plugin/helloworld/src/main/java/org/zstack/plugin/example/APIHelloWorldMsg.java create mode 100755 plugin/helloworld/src/main/java/org/zstack/plugin/example/Greeting.java create mode 100755 plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingBase.java create mode 100755 plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingInventory.java create mode 100755 plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingMessage.java create mode 100755 plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingVO.java create mode 100755 plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingVO_.java create mode 100755 plugin/helloworld/src/main/java/org/zstack/plugin/example/HelloWorldApiInterceptor.java create mode 100755 plugin/helloworld/src/main/java/org/zstack/plugin/example/HelloWorldManager.java create mode 100755 plugin/helloworld/src/main/java/org/zstack/plugin/example/HelloWorldManagerImpl.java diff --git a/conf/serviceConfig/helloworld.xml b/conf/serviceConfig/helloworld.xml new file mode 100644 index 00000000000..4ee40379d65 --- /dev/null +++ b/conf/serviceConfig/helloworld.xml @@ -0,0 +1,13 @@ + + + helloworld + HelloWorldApiInterceptor + + + org.zstack.plugin.example.APIHelloWorldMsg + + + + org.zstack.plugin.example.APICreateGreetingMsg + + \ No newline at end of file diff --git a/conf/springConfigXml/helloworld.xml b/conf/springConfigXml/helloworld.xml new file mode 100644 index 00000000000..6f55b01789a --- /dev/null +++ b/conf/springConfigXml/helloworld.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/conf/zstack.xml b/conf/zstack.xml index a4bd0a088b8..f099fe1d067 100755 --- a/conf/zstack.xml +++ b/conf/zstack.xml @@ -119,4 +119,5 @@ + diff --git a/plugin/helloworld/pom.xml b/plugin/helloworld/pom.xml new file mode 100755 index 00000000000..b476f9ac9b0 --- /dev/null +++ b/plugin/helloworld/pom.xml @@ -0,0 +1,77 @@ + + + + plugin + org.zstack + 4.10.0 + + 4.0.0 + + helloworld + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${project.compiler.version} + + groovy-eclipse-compiler + ${project.java.version} + ${project.java.version} + lines,vars,source + true + + + + org.codehaus.groovy + groovy-eclipse-compiler + ${groovy.eclipse.compiler} + + + org.codehaus.groovy + groovy-eclipse-batch + ${groovy.eclipse.batch} + + + + + org.codehaus.mojo + aspectj-maven-plugin + ${aspectj.plugin.version} + + + + compile + test-compile + + + + + ${project.java.version} + ${project.java.version} + ${project.java.version} + true + + + org.springframework + spring-aspects + + + org.zstack + core + + + org.zstack + header + + + + + + + + \ No newline at end of file diff --git a/plugin/helloworld/src/main/java/org/zstack/plugin/example/APICreateGreetingEvent.java b/plugin/helloworld/src/main/java/org/zstack/plugin/example/APICreateGreetingEvent.java new file mode 100755 index 00000000000..6016d8a9523 --- /dev/null +++ b/plugin/helloworld/src/main/java/org/zstack/plugin/example/APICreateGreetingEvent.java @@ -0,0 +1,24 @@ +package org.zstack.plugin.example; + +import org.zstack.header.message.APIEvent; +import org.zstack.header.rest.RestResponse; + +@RestResponse(allTo = "inventory") +public class APICreateGreetingEvent extends APIEvent { + private GreetingInventory inventory; + + public APICreateGreetingEvent() { + } + + public APICreateGreetingEvent(String apiId) { + super(apiId); + } + + public GreetingInventory getInventory() { + return inventory; + } + + public void setInventory(GreetingInventory inventory) { + this.inventory = inventory; + } +} diff --git a/plugin/helloworld/src/main/java/org/zstack/plugin/example/APICreateGreetingMsg.java b/plugin/helloworld/src/main/java/org/zstack/plugin/example/APICreateGreetingMsg.java new file mode 100755 index 00000000000..f600ff7d579 --- /dev/null +++ b/plugin/helloworld/src/main/java/org/zstack/plugin/example/APICreateGreetingMsg.java @@ -0,0 +1,21 @@ +package org.zstack.plugin.example; + +import org.springframework.http.HttpMethod; +import org.zstack.header.message.APICreateMessage; +import org.zstack.header.message.APIParam; +import org.zstack.header.rest.RestRequest; + + +@RestRequest(path = "/helloworld/greetings", method = HttpMethod.POST, responseClass = APICreateGreetingEvent.class, parameterName = "params") +public class APICreateGreetingMsg extends APICreateMessage { + @APIParam(emptyString = false) + private String greeting; + + public String getGreeting() { + return greeting; + } + + public void setGreeting(String greeting) { + this.greeting = greeting; + } +} diff --git a/plugin/helloworld/src/main/java/org/zstack/plugin/example/APIDeleteGreetingEvent.java b/plugin/helloworld/src/main/java/org/zstack/plugin/example/APIDeleteGreetingEvent.java new file mode 100755 index 00000000000..9b97a4818e9 --- /dev/null +++ b/plugin/helloworld/src/main/java/org/zstack/plugin/example/APIDeleteGreetingEvent.java @@ -0,0 +1,14 @@ +package org.zstack.plugin.example; + +import org.zstack.header.message.APIEvent; +import org.zstack.header.rest.RestResponse; + +@RestResponse +public class APIDeleteGreetingEvent extends APIEvent { + public APIDeleteGreetingEvent() { + } + + public APIDeleteGreetingEvent(String apiId) { + super(apiId); + } +} diff --git a/plugin/helloworld/src/main/java/org/zstack/plugin/example/APIDeleteGreetingMsg.java b/plugin/helloworld/src/main/java/org/zstack/plugin/example/APIDeleteGreetingMsg.java new file mode 100755 index 00000000000..d2cb9466b14 --- /dev/null +++ b/plugin/helloworld/src/main/java/org/zstack/plugin/example/APIDeleteGreetingMsg.java @@ -0,0 +1,23 @@ +package org.zstack.plugin.example; + +import org.springframework.http.HttpMethod; +import org.zstack.header.message.APIDeleteMessage; +import org.zstack.header.rest.RestRequest; + +@RestRequest(path = "/helloworld/greetings/{uuid}", method = HttpMethod.DELETE, responseClass = APIDeleteGreetingEvent.class) +public class APIDeleteGreetingMsg extends APIDeleteMessage implements GreetingMessage { + private String uuid; + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + @Override + public String getGreetingUuid() { + return uuid; + } +} diff --git a/plugin/helloworld/src/main/java/org/zstack/plugin/example/APIHelloWorldEvent.java b/plugin/helloworld/src/main/java/org/zstack/plugin/example/APIHelloWorldEvent.java new file mode 100755 index 00000000000..1b8e526e2fa --- /dev/null +++ b/plugin/helloworld/src/main/java/org/zstack/plugin/example/APIHelloWorldEvent.java @@ -0,0 +1,24 @@ +package org.zstack.plugin.example; + +import org.zstack.header.message.APIEvent; +import org.zstack.header.rest.RestResponse; + +@RestResponse(allTo = "greeting") +public class APIHelloWorldEvent extends APIEvent { + private String greeting; + + public APIHelloWorldEvent() { + } + + public APIHelloWorldEvent(String apiId) { + super(apiId); + } + + public String getGreeting() { + return greeting; + } + + public void setGreeting(String greeting) { + this.greeting = greeting; + } +} \ No newline at end of file diff --git a/plugin/helloworld/src/main/java/org/zstack/plugin/example/APIHelloWorldMsg.java b/plugin/helloworld/src/main/java/org/zstack/plugin/example/APIHelloWorldMsg.java new file mode 100755 index 00000000000..da082f429bc --- /dev/null +++ b/plugin/helloworld/src/main/java/org/zstack/plugin/example/APIHelloWorldMsg.java @@ -0,0 +1,20 @@ +package org.zstack.plugin.example; + +import org.springframework.http.HttpMethod; +import org.zstack.header.message.APIMessage; +import org.zstack.header.message.APIParam; +import org.zstack.header.rest.RestRequest; + +@RestRequest(path = "/helloworld/greetings", method = HttpMethod.POST, responseClass = APIHelloWorldEvent.class) +public class APIHelloWorldMsg extends APIMessage { + @APIParam(maxLength = 255) + private String greeting; + + public String getGreeting() { + return greeting; + } + + public void setGreeting(String greeting) { + this.greeting = greeting; + } +} \ No newline at end of file diff --git a/plugin/helloworld/src/main/java/org/zstack/plugin/example/Greeting.java b/plugin/helloworld/src/main/java/org/zstack/plugin/example/Greeting.java new file mode 100755 index 00000000000..1b9eb8b72c9 --- /dev/null +++ b/plugin/helloworld/src/main/java/org/zstack/plugin/example/Greeting.java @@ -0,0 +1,7 @@ +package org.zstack.plugin.example; + +import org.zstack.header.message.Message; + +public interface Greeting { + void handleMessage(Message msg); +} diff --git a/plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingBase.java b/plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingBase.java new file mode 100755 index 00000000000..6e793d7874a --- /dev/null +++ b/plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingBase.java @@ -0,0 +1,50 @@ +package org.zstack.plugin.example; + +import org.springframework.beans.factory.annotation.Autowire; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Configurable; +import org.zstack.core.cloudbus.CloudBus; +import org.zstack.core.db.DatabaseFacade; +import org.zstack.header.message.APIMessage; +import org.zstack.header.message.Message; + +@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE) +public class GreetingBase implements Greeting { + protected GreetingVO self; + + @Autowired + protected CloudBus bus; + @Autowired + protected DatabaseFacade dbf; + + public GreetingBase(GreetingVO self) { + this.self = self; + } + + @Override + public void handleMessage(Message msg) { + if (msg instanceof APIMessage) { + handleApiMessage((APIMessage) msg); + } else { + handleLocalMessage(msg); + } + } + + private void handleLocalMessage(Message msg) { + bus.dealWithUnknownMessage(msg); + } + + private void handleApiMessage(APIMessage msg) { + if (msg instanceof APIDeleteGreetingMsg) { + handle((APIDeleteGreetingMsg) msg); + } else { + bus.dealWithUnknownMessage(msg); + } + } + + private void handle(APIDeleteGreetingMsg msg) { + dbf.remove(self); + + bus.publish(new APIDeleteGreetingEvent(msg.getId())); + } +} diff --git a/plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingInventory.java b/plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingInventory.java new file mode 100755 index 00000000000..f310cfeb7e9 --- /dev/null +++ b/plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingInventory.java @@ -0,0 +1,61 @@ +package org.zstack.plugin.example; + +import org.zstack.header.search.Inventory; + +import java.sql.Timestamp; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +@Inventory(mappingVOClass = GreetingVO.class) +public class GreetingInventory { + private String uuid; + private String greeting; + private Timestamp lastOpDate; + private Timestamp createDate; + + public static GreetingInventory valueOf(GreetingVO vo) { + GreetingInventory inv = new GreetingInventory(); + inv.uuid = vo.getUuid(); + inv.greeting = vo.getGreeting(); + inv.lastOpDate = vo.getLastOpDate(); + inv.createDate = vo.getCreateDate(); + return inv; + } + + public static List valueOf(Collection vos) { + return vos.stream().map(GreetingInventory::valueOf).collect(Collectors.toList()); + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getGreeting() { + return greeting; + } + + public void setGreeting(String greeting) { + this.greeting = greeting; + } + + public Timestamp getLastOpDate() { + return lastOpDate; + } + + public void setLastOpDate(Timestamp lastOpDate) { + this.lastOpDate = lastOpDate; + } + + public Timestamp getCreateDate() { + return createDate; + } + + public void setCreateDate(Timestamp createDate) { + this.createDate = createDate; + } +} diff --git a/plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingMessage.java b/plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingMessage.java new file mode 100755 index 00000000000..23f52211e39 --- /dev/null +++ b/plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingMessage.java @@ -0,0 +1,5 @@ +package org.zstack.plugin.example; + +public interface GreetingMessage { + String getGreetingUuid(); +} diff --git a/plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingVO.java b/plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingVO.java new file mode 100755 index 00000000000..615bc6954b4 --- /dev/null +++ b/plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingVO.java @@ -0,0 +1,51 @@ +package org.zstack.plugin.example; + +import org.zstack.header.vo.ResourceVO; +import org.zstack.header.vo.ToInventory; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.PreUpdate; +import javax.persistence.Table; +import java.sql.Timestamp; + +@Entity +@Table +public class GreetingVO extends ResourceVO implements ToInventory { + @Column + private String greeting; + + @Column + private Timestamp lastOpDate; + @Column + private Timestamp createDate; + + @PreUpdate + void preUpdate() { + lastOpDate = null; + } + + public String getGreeting() { + return greeting; + } + + public void setGreeting(String greeting) { + this.greeting = greeting; + } + + public Timestamp getLastOpDate() { + return lastOpDate; + } + + public void setLastOpDate(Timestamp lastOpDate) { + this.lastOpDate = lastOpDate; + } + + public Timestamp getCreateDate() { + return createDate; + } + + public void setCreateDate(Timestamp createDate) { + this.createDate = createDate; + } +} diff --git a/plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingVO_.java b/plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingVO_.java new file mode 100755 index 00000000000..8dee790974c --- /dev/null +++ b/plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingVO_.java @@ -0,0 +1,14 @@ +package org.zstack.plugin.example; + + import org.zstack.header.vo.ResourceVO_; + + import javax.persistence.metamodel.SingularAttribute; + import javax.persistence.metamodel.StaticMetamodel; + import java.sql.Timestamp; + +@StaticMetamodel(GreetingVO.class) +public class GreetingVO_ extends ResourceVO_ { + public static volatile SingularAttribute greeting; + public static volatile SingularAttribute lastOpDate; + public static volatile SingularAttribute createDate; +} diff --git a/plugin/helloworld/src/main/java/org/zstack/plugin/example/HelloWorldApiInterceptor.java b/plugin/helloworld/src/main/java/org/zstack/plugin/example/HelloWorldApiInterceptor.java new file mode 100755 index 00000000000..4c93ae797da --- /dev/null +++ b/plugin/helloworld/src/main/java/org/zstack/plugin/example/HelloWorldApiInterceptor.java @@ -0,0 +1,23 @@ +package org.zstack.plugin.example; + +import org.zstack.header.apimediator.ApiMessageInterceptionException; +import org.zstack.header.apimediator.ApiMessageInterceptor; +import org.zstack.header.message.APIMessage; +import static org.zstack.core.Platform.argerr; + +public class HelloWorldApiInterceptor implements ApiMessageInterceptor { + @Override + public APIMessage intercept(APIMessage msg) throws ApiMessageInterceptionException { + if (msg instanceof APIHelloWorldMsg) { + validate((APIHelloWorldMsg) msg); + } + + return msg; + } + + private void validate(APIHelloWorldMsg msg) { + if (msg.getGreeting() == null || msg.getGreeting().isEmpty()) { + throw new ApiMessageInterceptionException(argerr("greeting cannot be null or empty")); + } + } +} diff --git a/plugin/helloworld/src/main/java/org/zstack/plugin/example/HelloWorldManager.java b/plugin/helloworld/src/main/java/org/zstack/plugin/example/HelloWorldManager.java new file mode 100755 index 00000000000..6001568a3e5 --- /dev/null +++ b/plugin/helloworld/src/main/java/org/zstack/plugin/example/HelloWorldManager.java @@ -0,0 +1,5 @@ +package org.zstack.plugin.example; + +public interface HelloWorldManager { + String SERVICE_ID = "helloworld"; +} diff --git a/plugin/helloworld/src/main/java/org/zstack/plugin/example/HelloWorldManagerImpl.java b/plugin/helloworld/src/main/java/org/zstack/plugin/example/HelloWorldManagerImpl.java new file mode 100755 index 00000000000..9fc98db0628 --- /dev/null +++ b/plugin/helloworld/src/main/java/org/zstack/plugin/example/HelloWorldManagerImpl.java @@ -0,0 +1,93 @@ +package org.zstack.plugin.example; + +import org.springframework.beans.factory.annotation.Autowired; +import org.zstack.core.Platform; +import org.zstack.core.cloudbus.CloudBus; +import org.zstack.core.cloudbus.MessageSafe; +import org.zstack.core.db.DatabaseFacade; +import org.zstack.header.AbstractService; +import org.zstack.header.Component; +import org.zstack.header.errorcode.OperationFailureException; +import org.zstack.header.message.APIMessage; +import org.zstack.header.message.Message; +import org.zstack.utils.Utils; +import org.zstack.utils.logging.CLogger; +import static org.zstack.core.Platform.operr; + +public class HelloWorldManagerImpl extends AbstractService implements HelloWorldManager, Component { + private static final CLogger logger = Utils.getLogger(HelloWorldManagerImpl.class); + + @Autowired + private CloudBus bus; + @Autowired + private DatabaseFacade dbf; + + @Override + @MessageSafe + public void handleMessage(Message msg) { + if (msg instanceof GreetingMessage) { + passThrough((GreetingMessage) msg); + } else if (msg instanceof APIMessage) { + handleAPIMessage((APIMessage) msg); + } else { + handleLocalMessage(msg); + } + } + + private void passThrough(GreetingMessage msg) { + GreetingVO vo = dbf.findByUuid(msg.getGreetingUuid(), GreetingVO.class); + if (vo == null) { + throw new OperationFailureException(operr("cannot find GreetingVO[uuid:%s], it may have been deleted", msg.getGreetingUuid())); + } + + new GreetingBase(vo).handleMessage((Message) msg); + } + + private void handleLocalMessage(Message msg) { + bus.dealWithUnknownMessage(msg); + } + + private void handleAPIMessage(APIMessage msg) { + if (msg instanceof APIHelloWorldMsg) { + handle((APIHelloWorldMsg) msg); + } else if (msg instanceof APICreateGreetingMsg) { + handle((APICreateGreetingMsg) msg); + } else { + bus.dealWithUnknownMessage(msg); + } + } + + private void handle(APICreateGreetingMsg msg) { + GreetingVO vo = new GreetingVO(); + vo.setUuid(msg.getResourceUuid() == null ? Platform.getUuid() : msg.getResourceUuid()); + vo.setGreeting(msg.getGreeting()); + vo = dbf.updateAndRefresh(vo); + + APICreateGreetingEvent evt = new APICreateGreetingEvent(msg.getId()); + evt.setInventory(vo.toInventory()); + bus.publish(evt); + } + + private void handle(APIHelloWorldMsg msg) { + logger.debug(String.format("say hello: %s", msg)); + + APIHelloWorldEvent evt = new APIHelloWorldEvent(msg.getId()); + evt.setGreeting(msg.getGreeting()); + bus.publish(evt); + } + + @Override + public String getId() { + return bus.makeLocalServiceId(SERVICE_ID); + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } +}