Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions conf/serviceConfig/helloworld.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<service xmlns="http://zstack.org/schema/zstack">
<id>helloworld</id>
<interceptor>HelloWorldApiInterceptor</interceptor>

<message>
<name>org.zstack.plugin.example.APIHelloWorldMsg</name>
</message>

<message>
<name>org.zstack.plugin.example.APICreateGreetingMsg</name>
</message>
</service>
27 changes: 27 additions & 0 deletions conf/springConfigXml/helloworld.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:zstack="http://zstack.org/schema/zstack"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://zstack.org/schema/zstack
http://zstack.org/schema/zstack/plugin.xsd"
default-init-method="init" default-destroy-method="destroy">

<bean id="HelloWorldManager" class="org.zstack.plugin.example.HelloWorldManagerImpl" >
<zstack:plugin>
<zstack:extension interface="org.zstack.header.Component" />
<zstack:extension interface="org.zstack.header.Service" />
</zstack:plugin>
</bean>

<bean id="HelloWorldApiInterceptor" class="org.zstack.plugin.example.HelloWorldApiInterceptor" >
<zstack:plugin>
<zstack:extension interface="org.zstack.header.apimediator.ApiMessageInterceptor"/>
</zstack:plugin>
</bean>
</beans>
1 change: 1 addition & 0 deletions conf/zstack.xml
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,5 @@
<import resource="springConfigXml/sugonSdnController.xml"/>
<import resource="springConfigXml/TfPortAllocator.xml"/>
<import resource="springConfigXml/HostNetworkManager.xml"/>
<import resource="springConfigXml/helloworld.xml"/>
</beans>
77 changes: 77 additions & 0 deletions plugin/helloworld/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>plugin</artifactId>
<groupId>org.zstack</groupId>
<version>4.10.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>helloworld</artifactId>


<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${project.compiler.version}</version>
<configuration>
<compilerId>groovy-eclipse-compiler</compilerId>
<source>${project.java.version}</source>
<target>${project.java.version}</target>
<debuglevel>lines,vars,source</debuglevel>
<debug>true</debug>
</configuration>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-compiler</artifactId>
<version>${groovy.eclipse.compiler}</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-batch</artifactId>
<version>${groovy.eclipse.batch}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>${aspectj.plugin.version}</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<source>${project.java.version}</source>
<target>${project.java.version}</target>
<complianceLevel>${project.java.version}</complianceLevel>
<XnoInline>true</XnoInline>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
<aspectLibrary>
<groupId>org.zstack</groupId>
<artifactId>core</artifactId>
</aspectLibrary>
<aspectLibrary>
<groupId>org.zstack</groupId>
<artifactId>header</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
Comment on lines +9 to +20
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

缺少 __example__,API 文档生成受阻。

API 消息类需要提供 __example__ 以生成文档与模板。建议补充示例方法。

🧩 建议补充
 public class APICreateGreetingMsg extends APICreateMessage {
     `@APIParam`(emptyString = false)
     private String greeting;
@@
     public void setGreeting(String greeting) {
         this.greeting = greeting;
     }
+
+    public static APICreateGreetingMsg __example__() {
+        APICreateGreetingMsg msg = new APICreateGreetingMsg();
+        msg.setGreeting("hello zstack");
+        return msg;
+    }
 }

基于编码规范。

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@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;
}
`@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;
}
public static APICreateGreetingMsg __example__() {
APICreateGreetingMsg msg = new APICreateGreetingMsg();
msg.setGreeting("hello zstack");
return msg;
}
}
🤖 Prompt for AI Agents
In
`@plugin/helloworld/src/main/java/org/zstack/plugin/example/APICreateGreetingMsg.java`
around lines 9 - 20, The APICreateGreetingMsg class lacks the required static
__example__ method used for API doc generation; add a public static
APICreateGreetingMsg __example__() that constructs and returns an instance with
a representative greeting (e.g., "hello world") set via setGreeting, so
documentation and templates can be generated from this example; implement the
method inside the APICreateGreetingMsg class.

}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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;
Comment on lines +3 to +16
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

为 uuid 补充 @APIParam 以启用资源校验/权限检查。
未标注 resourceType/checkAccount 可能导致资源类型与账号校验缺失,删除类接口风险较高,建议补充。

🔧 建议补充参数校验注解
 import org.springframework.http.HttpMethod;
 import org.zstack.header.message.APIDeleteMessage;
+import org.zstack.header.message.APIParam;
 import org.zstack.header.rest.RestRequest;
 
 `@RestRequest`(path = "/helloworld/greetings/{uuid}", method = HttpMethod.DELETE, responseClass = APIDeleteGreetingEvent.class)
 public class APIDeleteGreetingMsg extends APIDeleteMessage implements GreetingMessage {
+    `@APIParam`(resourceType = GreetingVO.class, checkAccount = true)
     private String uuid;
🤖 Prompt for AI Agents
In
`@plugin/helloworld/src/main/java/org/zstack/plugin/example/APIDeleteGreetingMsg.java`
around lines 3 - 16, APIDeleteGreetingMsg 中的 uuid
缺少资源校验注解,导致删除接口无法触发资源类型与账号权限校验;在 APIDeleteGreetingMsg 类的 uuid 字段上添加
`@APIParam`(resourceType = GreetingVO.class, checkAccount = true)(或项目中对应的资源 VO
类型)以启用资源类型校验和账号检查,并确保 getter/setter 保持不变以避免序列化问题;确认导入对应的 `@APIParam` 注解和资源 VO
类(引用类名:APIDeleteGreetingMsg、uuid、GreetingMessage、APIDeleteMessage、GreetingVO)。

}

@Override
public String getGreetingUuid() {
return uuid;
}
Comment on lines +8 to +22
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

补充 example 以生成 API 文档。
建议按现有示例模式添加 example。As per coding guidelines, 需补充 example 方法。

🧩 建议补充 __example__
     `@Override`
     public String getGreetingUuid() {
         return uuid;
     }
+
+    public static APIDeleteGreetingMsg __example__() {
+        APIDeleteGreetingMsg msg = new APIDeleteGreetingMsg();
+        msg.setUuid("c3f5e3b7b1fd4b1f9b6c2f3f1a2b3c4d");
+        return msg;
+    }
 }
🤖 Prompt for AI Agents
In
`@plugin/helloworld/src/main/java/org/zstack/plugin/example/APIDeleteGreetingMsg.java`
around lines 8 - 22, Add a static __example__ method to APIDeleteGreetingMsg
that returns a populated example instance (following other API classes' pattern)
so the API docs can be generated; implement it in the APIDeleteGreetingMsg class
(alongside getGreetingUuid) to construct a new APIDeleteGreetingMsg, set a
sample uuid (use the same sample/uuid helper or a realistic placeholder used in
other examples), and return that instance.

}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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 {
Comment on lines +8 to +9
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

与 APICreateGreetingMsg 的 REST 路径/方法冲突。
当前 POST /helloworld/greetings 被两个消息复用,路由可能歧义或覆盖,建议改为唯一路径或不同方法。

🔧 建议调整为唯一 REST 路径
-@RestRequest(path = "/helloworld/greetings", method = HttpMethod.POST, responseClass = APIHelloWorldEvent.class)
+@RestRequest(path = "/helloworld/greetings/actions/hello", method = HttpMethod.POST, responseClass = APIHelloWorldEvent.class)
 public class APIHelloWorldMsg extends APIMessage {
🤖 Prompt for AI Agents
In
`@plugin/helloworld/src/main/java/org/zstack/plugin/example/APIHelloWorldMsg.java`
around lines 8 - 9, The REST mapping for APIHelloWorldMsg conflicts with
APICreateGreetingMsg because both use POST "/helloworld/greetings"; update
APIHelloWorldMsg's `@RestRequest` annotation to a unique path or HTTP method
(e.g., change path to "/helloworld/hello" or use GET) so routes are unambiguous,
then adjust the APIHelloWorldMsg class annotation and any related
client/tests/docs that reference the old path to match the new endpoint; ensure
you modify the `@RestRequest` on APIHelloWorldMsg and any routing/tests that
assert POST "/helloworld/greetings".

@APIParam(maxLength = 255)
private String greeting;

public String getGreeting() {
return greeting;
}

public void setGreeting(String greeting) {
this.greeting = greeting;
}
Comment on lines +9 to +19
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

补充 example 以生成 API 文档。
缺少 example 会导致文档/模板缺失。As per coding guidelines, 需补充 example 方法。

🧩 建议补充 __example__
     public void setGreeting(String greeting) {
         this.greeting = greeting;
     }
+
+    public static APIHelloWorldMsg __example__() {
+        APIHelloWorldMsg msg = new APIHelloWorldMsg();
+        msg.setGreeting("hello");
+        return msg;
+    }
 }
🤖 Prompt for AI Agents
In
`@plugin/helloworld/src/main/java/org/zstack/plugin/example/APIHelloWorldMsg.java`
around lines 9 - 19, Add a static example() factory to APIHelloWorldMsg so API
docs/templates are generated: implement a public static APIHelloWorldMsg
example() method that creates a new APIHelloWorldMsg instance, sets a
representative greeting (e.g., "hello world" or similar) via setGreeting, and
returns the instance; place this method inside the APIHelloWorldMsg class to
satisfy the documentation generator expectations.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.zstack.plugin.example;

import org.zstack.header.message.Message;

public interface Greeting {
void handleMessage(Message msg);
Comment on lines +5 to +6
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

接口方法缺少 Javadoc。

接口方法需配套有效 Javadoc,以满足规范与文档生成要求。

📝 建议补充
 public interface Greeting {
+    /**
+     * 处理 Greeting 相关消息
+     */
     void handleMessage(Message msg);
 }

基于编码规范。

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public interface Greeting {
void handleMessage(Message msg);
public interface Greeting {
/**
* 处理 Greeting 相关消息
*/
void handleMessage(Message msg);
🤖 Prompt for AI Agents
In `@plugin/helloworld/src/main/java/org/zstack/plugin/example/Greeting.java`
around lines 5 - 6, 接口方法 Greeting.handleMessage 缺少 Javadoc;请为该接口方法补充规范的 Javadoc
注释,描述方法的用途、参数(Message msg 的语义和可能的取值/状态)、异常行为或抛出的异常(如有),以及必要时描述线程/调用约束或返回语义(尽管为
void)。确保注释格式符合项目约定(@param、@throws 等标签),并添加在 Greeting 接口的 handleMessage 方法声明上。

}
Original file line number Diff line number Diff line change
@@ -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()));
}
}
Original file line number Diff line number Diff line change
@@ -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<GreetingInventory> valueOf(Collection<GreetingVO> 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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.zstack.plugin.example;

public interface GreetingMessage {
String getGreetingUuid();
Comment on lines +3 to +4
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

接口方法缺少 Javadoc。

接口方法需配套有效 Javadoc,以满足规范与文档生成要求。

📝 建议补充
 public interface GreetingMessage {
+    /**
+     * 获取 Greeting 资源 UUID
+     */
     String getGreetingUuid();
 }

基于编码规范。

🤖 Prompt for AI Agents
In
`@plugin/helloworld/src/main/java/org/zstack/plugin/example/GreetingMessage.java`
around lines 3 - 4, GreetingMessage 接口的方法 getGreetingUuid 缺少
Javadoc;请为接口和其方法补充完整的 Javadoc 注释,描述接口用途、方法功能、返回值含义(UUID
的格式/用途)以及任何异常或线程/并发相关的约束,确保在 GreetingMessage 接口文件顶部和 getGreetingUuid 方法签名上添加相应的
JavaDoc 块以满足文档和编码规范要求。

}
Loading