manage-java-events
暂无简介
- License 许可
- Apache-2.0
- 最近更新
- 2026-11-12
- Stars
- ★ 178
- Forks
- 222
02 资源文件 1
- 脚本suggest-compact.sh1.6 KB
03 SKILL.md 正文
<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -->
name: manage-java-events description: |-
- Implementing OFBiz Events (web boundaries) in Java.
- Handling HTTP requests, responses, and MVC flow.
- Requires manage-java-patterns for shared standards.
Skill: manage-java-events
Goal
Implement robust web request handling and control flow using Java Events in OFBiz. This is particularly suited for complex web requests requiring integration with Java libraries or complex pre-processing before calling services.
Triggers
ALWAYS read this skill when:
- Creating or modifying Java methods intended to be called as events by
controller.xml. - Interacting directly with
HttpServletRequestorHttpServletResponsein Java.
[!TIP] See manage-java-patterns for shared Java standards (logging, localization, and exception handling).
Rules & Procedures
1. Class Structure & Method Signature
- Static Methods: A Java Event must be a
public staticmethod. - Signature:
public static String myEvent(HttpServletRequest request, HttpServletResponse response). - Return Type: Always returns a
Stringmapping to<response>incontroller.xml(e.g.,"success","error","none").
2. Context & Input Handling
- Delegator/Dispatcher: Retrieve from request attributes.
Delegator delegator = (Delegator) request.getAttribute("delegator"); LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher"); - Security Context: Fetch
userLogin,locale, andtimeZonefrom request attributes/session.GenericValue userLogin = (GenericValue) request.getAttribute("userLogin"); if (userLogin == null) { userLogin = (GenericValue) request.getSession().getAttribute("userLogin"); } Locale locale = UtilHttp.getLocale(request); TimeZone timeZone = UtilHttp.getTimeZone(request);- Rule: Derive identity from the
userLoginobject, never from parameters.
- Rule: Derive identity from the
- Parameters: Use
request.getParameter("id")for single values orUtilHttp.getParameterMap(request)for bulk. - Rule: Consult manage-java-patterns for mandatory trimming and validation before passing data to services.
3. Response & Message Management
- Success Pattern: Set
_EVENT_MESSAGE_and return"success". - Error Pattern: Set
_ERROR_MESSAGE_or_ERROR_MESSAGE_LIST_and return"error". - AJAX/JSON Boundary:
- Set
response.setContentType("application/json")and HTTP status. - Write JSON directly to
response.getWriter(). - MUST return
"none"to stop further view rendering.
- Set
- Redirection: For
request-redirect, store messages in the session (request.getSession().setAttribute("_ERROR_MESSAGE_", ...)) to ensure they survive the redirect.
4. Uploads & Streaming
- Multipart Data: Standard
request.getParameter()returnsnullfor file uploads.- Rule: Use OFBiz upload utilities or request wrappers.
- Rule: Never read full files into memory; process as a stream.
- Direct Streaming: For file downloads, write directly to the response output stream and return
"none".
Guardrails
- Standard Response Strings: Stick to
"success","error", or"none". - Return "none": Required whenever the response is already committed (JSON, redirects, streaming).
- Localization: ALL user-facing messages MUST be localized. Refer to manage-java-patterns.
- Validation & Exceptions: Refer to manage-java-patterns for standard
UtilValidateusage and exception strategies. - CSRF & Identity: Ensure CSRF protection for state-changing requests. Derive identity from
userLoginto prevent spoofing.
Bad Practices & Anti-patterns
Anti-pattern: The "Fat Event" (Deep Business Logic)
Pitfall: Writing business logic (loops, calculations, direct DB commits) inside a Java Event. This makes the logic non-reusable and bypasses the service engine's transaction and ECA management.
- ❌ Bad (Logic in Event):
for (String id : ids) { GenericValue gv = delegator.findOne("MyEntity", UtilMisc.toMap("id", id), false); gv.set("statusId", "DONE"); gv.store(); } return "success"; - ✅ Good (Delegate to Service):
// Event only prepares input and calls service Map<String, Object> result = dispatcher.runSync("updateMyStatus", UtilMisc.toMap("ids", ids, "userLogin", userLogin)); return ServiceUtil.isError(result) ? "error" : "success";
Anti-pattern: Identity Spoofing (Trusting Parameters)
Pitfall: Using an ID passed in the request parameter (e.g., partyId, userId) to determine the identity or permissions of the caller. Parameters can be easily spoofed.
- ❌ Bad:
String partyId = request.getParameter("partyId"); // Security Risk: User can pass any partyId in the URL! GenericValue profile = delegator.findOne("Party", UtilMisc.toMap("partyId", partyId), false); - ✅ Good:
// Use the verified userLogin object from the session/request String partyId = userLogin.getString("partyId");
Anti-pattern: Standard Response Bypass
Pitfall: Returning non-standard strings or hardcoded message literals instead of using the controller flow and localized labels.
- ❌ Bad:
if (failure) return "Something went wrong"; // Breaks controller mapping - ✅ Good:
if (failure) { request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(...)); return "error"; // Correctly enters the error flow defined in controller.xml }
Other Bad Practices
- Assuming Form EncTypes: Using
request.getParameter()withmultipart/form-data(returnsnull). - Memory-Heavy Uploads: Reading a full
InputStreaminto memory; always use streaming. - Heavy Sessions: Storing large, non-essential objects in
HttpSession. - Assuming Auto-Transactions: Events do NOT handle transactions; use Services for atomicity.
Common Code Patterns (Examples)
Standard Java Event (Delegating to Service)
See how this event extracts context, validates, and hands off to the dispatcher:
public static String processOrderEvent(HttpServletRequest request, HttpServletResponse response) {
LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher");
Locale locale = UtilHttp.getLocale(request);
GenericValue userLogin = (GenericValue) request.getAttribute("userLogin");
String productId = request.getParameter("productId");
if (UtilValidate.isEmpty(productId)) {
request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage("UiLabels", "MissingProduct", locale));
return "error";
}
try {
Map<String, Object> serviceCtx = UtilMisc.toMap("productId", productId, "userLogin", userLogin, "locale", locale);
Map<String, Object> result = dispatcher.runSync("myOrderService", serviceCtx);
if (ServiceUtil.isError(result)) {
request.setAttribute("_ERROR_MESSAGE_", ServiceUtil.getErrorMessage(result));
return "error";
}
} catch (Exception e) {
Debug.logError(e, "Event Failure", MODULE);
request.setAttribute("_ERROR_MESSAGE_", "System Error");
return "error";
}
request.setAttribute("_EVENT_MESSAGE_", "Success");
return "success";
}
Redirect with Session-Based Messages
When using request-redirect, messages must be stored in the session to survive the redirect:
public static String redirectWithMsg(HttpServletRequest request, HttpServletResponse response) {
Locale locale = UtilHttp.getLocale(request);
String msg = UtilProperties.getMessage("MyLabels", "FormSubmitted", locale);
// Store in session for visibility after redirect
request.getSession().setAttribute("_EVENT_MESSAGE_", msg);
return "request-redirect";
}
Direct JSON Response for AJAX
public static String returnJsonResponse(HttpServletRequest request, HttpServletResponse response) {
Map<String, Object> data = UtilMisc.toMap("status", "ok", "timestamp", UtilDateTime.nowTimestamp());
try {
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.setHeader("Cache-Control", "no-store");
response.setStatus(HttpServletResponse.SC_OK);
// Use framework JSON utilities to serialize/write
// E.g., JSON.from(data).write(response.getWriter());
String json = // ... framework serialization ...
response.getWriter().write(json);
response.getWriter().flush();
} catch (Exception e) {
Debug.logError(e, "Error writing JSON response", MODULE);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
return "none"; // Stop further view rendering
}