Võ Văn Hải's blog

Chỉ có một điều tuyệt đối đó là mọi thứ đều tương đối…

EJB3 Entity Bean with JBOSS

Trong ví dụ này, tôi sẽ hướng dẫn cho các bạn cách thức tạo 1 ứng dụng JPA Entity Bean. Ứng dụng đựa trên nguyên tắc cơ bản của kiến trúc 3-tiers. Tầng Presentation (Client) truy xuất đến tầng Business Logic(Session Bean), Business Logic layer truy xuất dữ liệu thông qua Data Service (Entity Bean).

Software cần thiết:

  • Eclipse ganymede
  • JBoss Application Server 4.2.x

1. Đầu tiên, trong Eclipse bạn tiến hành tạo 1 project kiểu EJB Project. Chọn Target runtime là JBoss. Đặt tên là EJB3_Entity_Products như hình
https://vovanhai.files.wordpress.com/2008/10/ejb3_entity_011.png
2. Trong folder META-INF, tạo file persistence.xml với nội dung như sau


<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="EJB3_Entity_ProductsExample">
<jta-data-source>java:ejb3ProductDS</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect" />
</properties>
</persistence-unit>
</persistence>

Chú ý: ở đây chúng ta dùng jta-data-source java:ejb3ProductDS nên chúng ta cũng phải cấu hình cho data source này. Chúng ta muốn dùng hệ quản trị database là Microsoft SQL Server 2005 nên ta cần phải có driver cho cơ sở dữ liệu này, Bạn có thể download nó từ Microsoft hoặc download tại đây. Bạn hãy copy nó vào %JBOSS_HOME%\server\default\lib\. Sau đó tạo file mssql-ds.xml trong thư mục %JBOSS_HOME%\server\default\deploy\ (nếu đã có thì hiệu chỉnh file này) với nội dung sau

<?xml version=”1.0″ encoding=”UTF-8″?>
<datasources>
<local-tx-datasource>
<jndi-name>ejb3ProductDS</jndi-name>
<connection-url>jdbc:sqlserver://localhost:1433;databaseName=EJB3_JPA_Products</connection-url>
<driver-class>com.microsoft.sqlserver.jdbc.SQLServerDriver</driver-class>
<user-name>sa</user-name>
<password></password>
<metadata>
<type-mapping>MS SQLSERVER2000</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>

Thuộc tính <property name="hibernate.hbm2ddl.auto" value="update" /> phần value ta có thể có một trong các giá trị: validate | update | create | create-drop.

Thuộc tính <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect" /> chỉ cho hibernate biết Dialect là của Microsoft SQL Server.

Sau đây là bảng các SQL Dialect của Hibernate
https://vovanhai.files.wordpress.com/2008/10/hibernatedialect.png
3. Tạo Entity Bean

Tạo package vovanhai.wordpress.com

Tạo lớp Product.java trong gói này với nội dung:

package vovanhai.wordpress.com;import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity(name=”Product”)
public class Product implements Serializable{
private static final long serialVersionUID = 1L;
private int productID;
private String productName;
private String description;
private double basePrice;
public Product(int productID, String productName, String description,
double basePrice) {
super();
this.productID = productID;
this.productName = productName;
this.description = description;
this.basePrice = basePrice;
}
public Product() {
this(0,””,””,100f);
}
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public int getProductID() {
return productID;
}
public void setProductID(int productID) {
this.productID = productID;
}
@Column(name=”productName”, nullable=false )
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
@Column(name=”description”)
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Column(name=”basePrice”, nullable=false)
public double getBasePrice() {
return basePrice;
}
public void setBasePrice(double basePrice) {
this.basePrice = basePrice;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + productID;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Product other = (Product) obj;
if (productID != other.productID)
return false;
return true;
}
@Override
public String toString() {
return productID+”; “+productName+”; “+description+”; “+basePrice;
}
}

4. Tạo Stateless Session Bean

Tạo Remote interface, tập tin ProductRemote.java

package vovanhai.wordpress.com;import java.util.List;
import javax.ejb.Remote;

@Remote
public interface ProductRemote {
//Thêm 1 product vào database
public void AddNewProduct(Product p);
//Xóa 1 product khỏi database
public boolean RemoveProduct(int pID);
//Lấy tất cả các product từ bảng
public List<Product> GetAllProducts();
//Lấy tất cả các sản phẩm có giá dưới giá price
public List<Product> GetProductsUnderPrice(double price);
}

Tạo Local interface, tập tin ProductLocal.java

package vovanhai.wordpress.com;import java.util.List;
import javax.ejb.Local;

@Local
public interface ProductLocal {
public void AddNewProduct(Product p);
public boolean RemoveProduct(int pID);
public List<Product> GetAllProducts();
public List<Product> GetProductsUnderPrice(double price);
}

Tạo Session Bean, tập tin ProductBean.java

package vovanhai.wordpress.com;import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

@Stateless
public class ProductBean implements ProductRemote{

@PersistenceContext
EntityManager em;

@Override
public void AddNewProduct(Product p) {
em.persist(p);
}

@Override
public boolean RemoveProduct(int pID) {
Product p=em.find(Product.class, new Integer(pID));
if(p==null)
return false;
em.remove(p);
return true;
}

@SuppressWarnings(“all”)
@Override
public List<Product> GetAllProducts() {
List<Product> lst=(List<Product>)(em.createQuery(“from Product”).getResultList());
return lst;
}

@SuppressWarnings(“all”)
@Override
public List<Product> GetProductsUnderPrice(double price) {
Query query=em.createQuery(“from Product as p where p.basePrice< :price”);
query.setParameter(“price”, price);
List<Product> lst=(List<Product>)query.getResultList();
return lst;
}
}

OK! Triển khai nó trên JBOSS thôi. kết quả triển khai có dạng

20:36:05,212 INFO  [JmxKernelAbstraction] creating wrapper delegate for: org.jboss.ejb3.entity.PersistenceUnitDeployment
20:36:05,212 INFO  [JmxKernelAbstraction] installing MBean: persistence.units:jar=EJB3_Entity_Products.jar,unitName=EJB3_Entity_ProductsExample with dependencies:
20:36:05,212 INFO  [JmxKernelAbstraction]     jboss.jca:name=ejb3ProductDS,service=DataSourceBinding
20:36:05,212 INFO  [PersistenceUnitDeployment] Starting persistence unit persistence.units:jar=EJB3_Entity_Products.jar,unitName=EJB3_Entity_ProductsExample
20:36:05,213 INFO  [Ejb3Configuration] found EJB3 Entity bean: vovanhai.wordpress.com.Product
20:36:05,213 INFO  [Configuration] Reading mappings from resource : META-INF/orm.xml
20:36:05,213 INFO  [Ejb3Configuration] [PersistenceUnit: EJB3_Entity_ProductsExample] no META-INF/orm.xml found
20:36:05,213 INFO  [AnnotationBinder] Binding entity from annotated class: vovanhai.wordpress.com.Product
20:36:05,213 INFO  [EntityBinder] Bind entity vovanhai.wordpress.com.Product on table Product
20:36:05,244 INFO  [ConnectionProviderFactory] Initializing connection provider: org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider
20:36:05,244 INFO  [InjectedDataSourceConnectionProvider] Using provided datasource
20:36:06,695 INFO  [SettingsFactory] RDBMS: Microsoft SQL Server, version: 9.00.1399
20:36:06,695 INFO  [SettingsFactory] JDBC driver: Microsoft SQL Server 2005 JDBC Driver, version: 1.2.2828.100
20:36:06,695 INFO  [Dialect] Using dialect: org.hibernate.dialect.SQLServerDialect
20:36:06,710 INFO  [TransactionFactoryFactory] Transaction strategy: org.hibernate.ejb.transaction.JoinableCMTTransactionFactory
20:36:06,710 INFO  [TransactionManagerLookupFactory] instantiating TransactionManagerLookup: org.hibernate.transaction.JBossTransactionManagerLookup
20:36:06,710 INFO  [TransactionManagerLookupFactory] instantiated TransactionManagerLookup
20:36:06,711 INFO  [SettingsFactory] Automatic flush during beforeCompletion(): disabled
20:36:06,711 INFO  [SettingsFactory] Automatic session close at end of transaction: disabled
20:36:06,711 INFO  [SettingsFactory] Scrollable result sets: enabled
20:36:06,711 INFO  [SettingsFactory] JDBC3 getGeneratedKeys(): enabled
20:36:06,711 INFO  [SettingsFactory] Connection release mode: auto
20:36:06,711 INFO  [SettingsFactory] Default batch fetch size: 1
20:36:06,711 INFO  [SettingsFactory] Generate SQL with comments: disabled
20:36:06,711 INFO  [SettingsFactory] Order SQL updates by primary key: disabled
20:36:06,711 INFO  [SettingsFactory] Order SQL inserts for batching: disabled
20:36:06,711 INFO  [SettingsFactory] Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
20:36:06,711 INFO  [ASTQueryTranslatorFactory] Using ASTQueryTranslatorFactory
20:36:06,711 INFO  [SettingsFactory] Query language substitutions: {}
20:36:06,711 INFO  [SettingsFactory] JPA-QL strict compliance: enabled
20:36:06,711 INFO  [SettingsFactory] Second-level cache: enabled
20:36:06,711 INFO  [SettingsFactory] Query cache: disabled
20:36:06,711 INFO  [SettingsFactory] Cache provider: org.hibernate.cache.HashtableCacheProvider
20:36:06,711 INFO  [SettingsFactory] Optimize cache for minimal puts: disabled
20:36:06,711 INFO  [SettingsFactory] Cache region prefix: EJB3_Entity_Products_jar,EJB3_Entity_ProductsExample
20:36:06,711 INFO  [SettingsFactory] Structured second-level cache entries: disabled
20:36:06,711 INFO  [SettingsFactory] Statistics: disabled
20:36:06,711 INFO  [SettingsFactory] Deleted entity synthetic identifier rollback: disabled
20:36:06,711 INFO  [SettingsFactory] Default entity-mode: pojo
20:36:06,711 INFO  [SettingsFactory] Named query checking : enabled
20:36:06,711 INFO  [SessionFactoryImpl] building session factory
20:36:06,711 INFO  [SessionFactoryObjectFactory] Factory name: persistence.units:jar=EJB3_Entity_Products.jar,unitName=EJB3_Entity_ProductsExample
20:36:06,711 INFO  [NamingHelper] JNDI InitialContext properties:{java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory, java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces}
20:36:06,711 INFO  [SessionFactoryObjectFactory] Bound factory to JNDI name: persistence.units:jar=EJB3_Entity_Products.jar,unitName=EJB3_Entity_ProductsExample
20:36:06,711 WARN  [SessionFactoryObjectFactory] InitialContext did not implement EventContext
20:36:06,711 INFO  [SchemaUpdate] Running hbm2ddl schema update
20:36:06,711 INFO  [SchemaUpdate] fetching database metadata
20:36:06,743 INFO  [SchemaUpdate] updating schema
20:36:09,395 INFO  [TableMetadata] table found: EJB3_JPA_Products.dbo.Product
20:36:09,395 INFO  [TableMetadata] columns: [baseprice, productid, description, productname]
20:36:09,395 INFO  [TableMetadata] foreign keys: []
20:36:09,395 INFO  [TableMetadata] indexes: [pk__product__060deae8]
20:36:09,395 INFO  [SchemaUpdate] schema update complete
20:36:09,395 INFO  [NamingHelper] JNDI InitialContext properties:{java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory, java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces}
20:36:09,396 INFO  [JmxKernelAbstraction] creating wrapper delegate for: org.jboss.ejb3.stateless.StatelessContainer
20:36:09,396 INFO  [JmxKernelAbstraction] installing MBean: jboss.j2ee:jar=EJB3_Entity_Products.jar,name=ProductBean,service=EJB3 with dependencies:
20:36:09,396 INFO  [JmxKernelAbstraction]     persistence.units:jar=EJB3_Entity_Products.jar,unitName=EJB3_Entity_ProductsExample
20:36:09,396 INFO  [EJBContainer] STARTED EJB: vovanhai.wordpress.com.ProductBean ejbName: ProductBean
20:36:09,427 INFO  [EJB3Deployer] Deployed: file:/E:/javaSoft/jboss-4.2.3.GA/server/default/deploy/EJB3_Entity_Products.jar

Thành công rồi!

5. Viết client

Tạo lớp ProductClient với nội dung sau

package vovanhai.wordpress.com;import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class ProductClient {

public static void main(String[] args) {

System.setProperty(“java.naming.factory.initial”,”org.jnp.interfaces.NamingContextFactory”);
System.setProperty( “java.naming.provider.url”, “localhost:1099” );
System.setProperty( “java.naming.factory.url.pkgs”, “org.jboss.naming” );
Context context;
try
{
context = new InitialContext();
String name=”ProductBean/remote”;
ProductRemote beanRemote = (ProductRemote)context.lookup(name);
//Thêm 1 product mới
beanRemote.AddNewProduct(new Product(0,”Xoài”,”Xoài”,4000f));

System.out.println(“Danh sách sản phẩm”);
List<Product> lst=beanRemote.GetAllProducts();
for(Product p:lst)
System.out.println(p);

System.out.println(“Các sp có giá dưới 8000”);
lst=beanRemote.GetProductsUnderPrice(8000);
for(Product p:lst)
System.out.println(p);

//Xóa sản phẩm
/*if(beanRemote.RemoveProduct(4))
System.out.println(“Xóa thành công SP số 4”);
else
System.out.println(“Không xóa được sp số 4”);*/
} catch (NamingException e)
{
e.printStackTrace();
}
}
}

Thực thi ứng dụng và bạn sẽ ngạc nhiên đấy!

Chúc thành công!

41 Responses to “EJB3 Entity Bean with JBOSS”

  1. Nguyễn Thế Anh said

    Mình mới làm quen với ejb. Hiện tại mình đang dùng IDE là myeclipse. Ví dụ của bạn rất hay, mình có làm thử chỉ khác một chút là mình dùng DB là Oracle. Deploy thì rất ok, nhưng khi viết file client để test console thì thồi rồi (server jboss4.0.5)Lỗi như sau:
    javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
    at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645)
    at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:247)
    at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:284)
    at javax.naming.InitialContext.lookup(InitialContext.java:351)
    at com.myeclipseide.ejb.MyBeanClient.main(MyBeanClient.java:24)

    Xin chỉ giáo cách chỉnh sửa để cho chạy đc console. nó cứ đến phần Contextlookup

  2. vovanhai said

    Bạn thiếu các thư viện trong classpath. Có 1 cách rất hay là dùng Ant build nhưng với những người mới bắt đầu thì điều này hơi khó. Bạn nên thêm vào classpath đường dẫn đến những file jar trong thư mục %JBOSS_HOME%/client. Nếu bạn thấy mất công thì copy chúng vào %JAVA_HOME%\lib. Chúc thành công!

  3. hoangtrong said

    nếu dùng identity thì sao hả thầy

  4. EJB.0 Loi ket noi database said

    hi anh,
    anh cho em hỏi,khi em kết nối Entity của ejb3 với oracle database em dùng hàm :
    Class.forName(“oracle.jdbc.driver.OracleDriver”)

    thì khi gọi tới hàm của ejb thì nhận được thông báo lỗi:
    java.lang.ClassNotFoundException: No ClassLoaders found for: oracle.jdbc.driver.OracleDriver

    em đã add classes12.jar và ojdbc14.jar rồi. Em nhờ anh giải đáp giúp em nhé.

    P/s: Voi project bình thường thì không bị làm sao chỉ bị với ejb3 thui anh à.

    thanks anh.

  5. vovanhai said

    Copy file jar vào thư mục lib của project.
    chúc vui!

  6. Jenny said

    Em bị lỗi này, không hiều tại sao:

    javax.naming.CommunicationException: Could not obtain connection to any of these urls: localhost:1099 and discovery failed with error: javax.naming.CommunicationException: Receive timed out [Root exception is java.net.SocketTimeoutException: Receive timed out] [Root exception is javax.naming.CommunicationException: Failed to connect to server localhost:1099 [Root exception is javax.naming.ServiceUnavailableException: Failed to connect to server localhost:1099 [Root exception is java.net.ConnectException: Connection refused: connect]]]
    at org.jnp.interfaces.NamingContext.checkRef(NamingContext.java:1562)
    at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:634)
    at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:627)
    at javax.naming.InitialContext.lookup(Unknown Source)
    at jenny.ProductClient.main(ProductClient.java:20)
    Caused by: javax.naming.CommunicationException: Failed to connect to server localhost:1099 [Root exception is javax.naming.ServiceUnavailableException: Failed to connect to server localhost:1099 [Root exception is java.net.ConnectException: Connection refused: connect]]
    at org.jnp.interfaces.NamingContext.getServer(NamingContext.java:274)
    at org.jnp.interfaces.NamingContext.checkRef(NamingContext.java:1533)
    … 4 more
    Caused by: javax.naming.ServiceUnavailableException: Failed to connect to server localhost:1099 [Root exception is java.net.ConnectException: Connection refused: connect]
    at org.jnp.interfaces.NamingContext.getServer(NamingContext.java:248)
    … 5 more
    Caused by: java.net.ConnectException: Connection refused: connect
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.PlainSocketImpl.doConnect(Unknown Source)
    at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
    at java.net.PlainSocketImpl.connect(Unknown Source)
    at java.net.SocksSocketImpl.connect(Unknown Source)
    at java.net.Socket.connect(Unknown Source)
    at java.net.Socket.connect(Unknown Source)
    at java.net.Socket.(Unknown Source)
    at java.net.Socket.(Unknown Source)
    at org.jnp.interfaces.TimedSocketFactory.createSocket(TimedSocketFactory.java:84)
    at org.jnp.interfaces.TimedSocketFactory.createSocket(TimedSocketFactory.java:77)
    at org.jnp.interfaces.NamingContext.getServer(NamingContext.java:244)
    … 5 more

  7. vovanhai said

    có thể do chưa deploy thành công nên lookup không thấy hoặc server chưa khỏi động.

  8. Jenny said

    Buildfile: F:\eclipse\eclipse-jee-ganymede-SR1-win32\eclipse\plugins\org.eclipse.jst.server.generic.jboss_1.5.205.v200805140145\buildfiles\jboss323.xml
    deploy.j2ee.ejb:
    [jar] Building jar: E:\Hoc Tap\EJB lab\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\EJB3_Entity_Products.jar
    [move] Moving 1 file to E:\jboss\server\default\deploy
    BUILD SUCCESSFUL
    Total time: 10 seconds

    Kết quả sau khi chạy như trên, cho em hỏi làm thế nào thế được sự thay đổi?

  9. vovanhai said

    Trong server console bạn sẽ thấy gói jar của bạn triển khai. Tạo client để thử!

  10. duykhoatr said

    em có test lại hướng dẫn của anh thì thấy báo lỗi: EJBException not found Product entity

    sau khi em thêm dòng khai báo …Product trong persistence.xml thì chạy được anh à

  11. duykhoatr said

    em có test lại hướng dẫn của anh thì thấy báo lỗi: EJBException not found Product entity

    sau khi em thêm dòng khai báo

    …Product

    trong persistence.xml thì chạy được anh à

  12. duykhoatr said

    sao cái thẻ xml em ko chèn được nhỉ

    <class>
    …Product
    </class>

  13. TakarRashiro said

    Thầy ơi, cho em hỏi.

    Em muốn lập mô hình gồm 2 máy. 1 máy chạy jboss, 1 máy chạy client. Từ client em muốn truy xuất qua máy cài jboss để tìm Bean. Vậy em cần đổi cái localhost thành gì ạ? Em đã thử đặt ip máy jboss vào nhưng ko đc (vd: “192.168.1.10:1099”). Vậy em cần khai báo thế nào?

    System.setProperty( “java.naming.provider.url”, “localhost:1099″ );

    Code connect của em như sau:
    b_SecurityHome objHome;
    public boolean ConnSecurity() {
    boolean actionResult=false;
    try{
    System.setProperty(“java.naming.factory.initial”, “org.jnp.interfaces.NamingContextFactory”);
    System.setProperty(“java.naming.provider.url”, “localhost:1099”);
    System.setProperty(“java.naming.factory.url.pkgs”, “org.jboss.naming”);
    Context context=new InitialContext();

    Object objref=context.lookup(“NSSecurityBean”);
    objHome = (b_SecurityHome) PortableRemoteObject.narrow(objref,b_SecurityHome.class);

    actionResult=true;
    System.out.println(“.Process: Bean Server FOUND”);
    } catch (Exception e)
    {
    JOptionPane.showMessageDialog(this, “Không tìm thấy Bean Server.\n” +e.getMessage(), “Error”, JOptionPane.ERROR_MESSAGE);
    System.out.println(“.Error: Bean Server NOT FOUND:\n”+e.getMessage());
    e.printStackTrace();
    }
    return actionResult;
    }

  14. TakarRashiro said

    IP may jboss: 192.168.1.55. WinXP sp2. Đã tắt firewall. jboss ko thiết lập security gì cả. chỉ toàn bypass.

    javax.naming.CommunicationException: Could not obtain connection to any of these urls: 192.168.1.55:1099 and discovery failed with error: javax.naming.CommunicationException: Receive timed out [Root exception is java.net.SocketTimeoutException: Receive timed out] [Root exception is javax.naming.CommunicationException: Failed to connect to server 192.168.1.55:1099 [Root exception is javax.naming.ServiceUnavailableException: Failed to connect to server 192.168.1.55:1099 [Root exception is java.net.ConnectException: Connection refused: connect]]]
    at org.jnp.interfaces.NamingContext.checkRef(NamingContext.java:1604)
    at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:636)
    at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:629)
    at javax.naming.InitialContext.lookup(InitialContext.java:392)
    at firedrake.cl_UserLogin.ConnSecurity(cl_UserLogin.java:161)
    at firedrake.cl_UserLogin.jButton1ActionPerformed(cl_UserLogin.java:182)
    at firedrake.cl_UserLogin.access$000(cl_UserLogin.java:22)
    at firedrake.cl_UserLogin$1.actionPerformed(cl_UserLogin.java:71)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
    at java.awt.Component.processMouseEvent(Component.java:6263)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)
    at java.awt.Component.processEvent(Component.java:6028)
    at java.awt.Container.processEvent(Container.java:2041)
    at java.awt.Component.dispatchEventImpl(Component.java:4630)
    at java.awt.Container.dispatchEventImpl(Container.java:2099)
    at java.awt.Component.dispatchEvent(Component.java:4460)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4574)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4238)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168)
    at java.awt.Container.dispatchEventImpl(Container.java:2085)
    at java.awt.Window.dispatchEventImpl(Window.java:2478)
    at java.awt.Component.dispatchEvent(Component.java:4460)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:178)
    at java.awt.Dialog$1.run(Dialog.java:1046)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
    Caused by: javax.naming.CommunicationException: Failed to connect to server 192.168.1.55:1099 [Root exception is javax.naming.ServiceUnavailableException: Failed to connect to server 192.168.1.55:1099 [Root exception is java.net.ConnectException: Connection refused: connect]]
    at org.jnp.interfaces.NamingContext.getServer(NamingContext.java:276)
    at org.jnp.interfaces.NamingContext.checkRef(NamingContext.java:1575)
    … 38 more
    Caused by: javax.naming.ServiceUnavailableException: Failed to connect to server 192.168.1.55:1099 [Root exception is java.net.ConnectException: Connection refused: connect]
    at org.jnp.interfaces.NamingContext.getServer(NamingContext.java:250)
    … 39 more
    Caused by: java.net.ConnectException: Connection refused: connect
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
    at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
    at java.net.Socket.connect(Socket.java:525)
    at java.net.Socket.connect(Socket.java:475)
    at java.net.Socket.(Socket.java:372)
    at java.net.Socket.(Socket.java:273)
    at org.jnp.interfaces.TimedSocketFactory.createSocket(TimedSocketFactory.java:84)
    at org.jnp.interfaces.TimedSocketFactory.createSocket(TimedSocketFactory.java:77)
    at org.jnp.interfaces.NamingContext.getServer(NamingContext.java:246)
    … 39 more

  15. vovanhai said

    Chắc là do triển khai phần server chưa thành công nên JNDI không lookup được.

  16. vovanhai said

    EM phải đảm bảo 2 máy đó thấy nhau trước hết(phần cấu hình mạng em phải làm)
    Sau đó em start server trên 1 máy, triển khai ứng dụng của em trên đó. Đảm bảo mọi thứ OK(Có thể chạy JBOSS bằng cmd : run -b 192.168.1.1 (hay add của em)
    Chạy client trên máy kia.

  17. TakarRashiro said

    Cảm ơn thầy. Em làm được rồi.

  18. van tuan said

    Thầy cho em hỏi là khi em làm enterprise app khi build bằng netbean 6.8 thì trong META-INF không có file application.xml như khi làm với ejb2, phải copy bài khi làm bằng ejb2 vào thi mới chạy được không thì jboss nói thiếu file đó. Làm như demo của thầy khi em add new hoặc get all thì trong try catch nó bắt lỗi là null. Mong thầy chỉ giúp. Thanks

  19. vovanhai said

    NetBean 6.8 sử dụng J2EE6. Mọi thứ được thay bằng Annotation nen application.xml không còn cần thiết nữa. Nếu bạn làm EJB2 thì nên làm trên các version từ 6.71 trở về trước!

  20. van tuan said

    Thanks thầy, em làm được demo của thầy rồi nhưng mà là trên glassFish V3. Em đã làm demo đó trên cả JBoss 4.2.3 GA và 5.0.1 GA thì không được.
    Thầy cho em hỏi là khi 1 enterprise app chạy tốt trên JBoss, giờ muốn thay đổi server as (như glassFish chẳng hạn) hoặc ngược lại thì pải làm sao vậy thầy?
    Khi em làm trong netbean 6.8 chọn server là jboss thì nó build ra file .ear trong folder dist của ứng dụng. Khi chạy mà ko cần netbean thì em start jboss rồi lấy file .ear đó quăng vào folder deploy của jboss và gõ địa chỉ lên web và chạy được ứng dụng. Còn khi làm với glassFish thì không thấy file .ear hay folder deploy trong glassFish đâu cả nên giờ không biết run thế nào mà ko dùng đến netbean. Mong thầy chỉ giúp. Thanks thầy.

  21. EJB_JBoss said

    Thầy cho em hỏi, sao em làm giống hướng dẫn nhưng lúc chạy client để test thì vẫn không lookup được server.

  22. JVThanh said

    Thưa Thầy!
    Em làm EJB3 trên netbean 6.8 dùng server JBOSS, nhưng mỗi lúc em deploy web client thì bị báo lỗi là các port(như 1099,1098) đã được dùng nên không thể deploy, trong khi server đã started, em có đổi port trong file của jboss nhưng chỉ deploy được một lần, lần sau lại báo lỗi(em tắt server bằng cách close nó.Em phải làm sao để không bị như vậy nữa.Em mới làm quen với EJB nên mong Thầy giúp đỡ…
    Thanks Thầy

  23. Trung said

    Anh cho tôi hỏi, vì sao tôi luôn bị 2 lỗi này song song trong EJB 3.0 mà trong EJB 2.1 lại không bị, với cùng một source (hiện giờ cục jar deploy lên JBoss vẫn create table trong MySQL được, nhưng vẫn báo lỗi này):

    MBEANS THAT ARE THE ROOT CAUSE OF THE PROBLEM —
    ObjectName: jboss.j2ee:jar=StudentCourseService.jar,name=StudentServiceImpl,service=EJB3
    State: FAILED
    Reason: java.lang.RuntimeException: could not resolve global JNDI name for @EJB for container StudentServiceImpl: reference class: trung.studentcourse.dao.IStudentDAO ejbLink: not used by any EJBs

    ObjectName: jboss.j2ee:jar=StudentCourseService.jar,name=ClazzServiceImpl,service=EJB3
    State: FAILED
    Reason: java.lang.RuntimeException: could not resolve global JNDI name for @EJB for container ClazzServiceImpl: reference class: trung.studentcourse.dao.IClazzDAO ejbLink: duplicated in StudentCourseService.jar

    Code của tôi như vầy (giống nhau ở cả 2 session bean Student và Clazz):

    @Stateless
    @Remote(IStudentService.class)
    public class StudentServiceImpl implements IStudentService{

    @EJB
    private IStudentDAO studentDAO;
    ….

    Mong nhận được trả lời của anh. Cám ơn rất nhiều. Trung.

  24. vovanhai said

    Bạn xem lại cái tên của EJB. Tôi nghĩ có lẽ bạn đã triển khai trước đó 1 EJB cùng tên(JNDI name) nên mới xảy ra tình trạng này. Bạn thử xoá hết các gói EJB đã deploy tứoc đó ồi deploy lại hoặc đổi tên EJB.
    Chúc vui!

  25. FC said

    Em viết ứng dụng sử dụng ẸB3 deploy trên JBoss 4.2.2 thì chạy và lookup bình thường. Nhưng khi deploy trên JBoss 5.0.1 GA, thì khi run ko có lỗi gì, nhưng khi lookup từ client thì báo lỗi
    java.lang.ClassCastException: javax.naming.Reference cannot be cast to com.viettel.vegate.remotes.trans.ITransLog
    at com.vegate.test.Client.main(Client.java:45)
    Mong nhận được trả lời của anh. Cám ơn rất nhiều.

  26. myblinks said

    Em mới làm quen với EJB3.
    Em có tạo 1 ví dụ về EJB dùng EE5, netbean 6.8 và JBOSS như sau:

    TestRemote.java:

    @Remote
    public interface TestRemote {

    String hello(String str);

    }

    Test.java:

    @Stateless(name=”Test”)
    public class Test implements TestRemote {
    public String hello(String str) {
    return str;
    }
    }

    Và bên phía client: TestServlet.java

    public class TestServlet extends HttpServlet {
    @EJB private TestRemote testRemote;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    try {
    PrintWriter out = resp.getWriter();
    InitialContext ic = new InitialContext();
    testRemote = (TestRemote) ic.lookup(“remote”);
    out.print(testRemote.businessMethod(“chung nguyen huu”));
    } catch (NamingException ex) {
    Logger.getLogger(TestServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
    }
    }

    Khi chạy có thông báo lỗi như sau:
    org.jboss.deployment.DeploymentException: No META-INF/application.xml found
    at org.jboss.deployment.EARDeployer.init(EARDeployer.java:146)
    at org.jboss.deployment.MainDeployer.init(MainDeployer.java:872)
    at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:809)
    at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:782)
    at sun.reflect.GeneratedMethodAccessor21.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
    at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
    at org.jboss.mx.interceptor.AbstractInterceptor.invoke(AbstractInterceptor.java:133)
    at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
    at org.jboss.mx.interceptor.ModelMBeanOperationInterceptor.invoke(ModelMBeanOperationInterceptor.java:142)
    at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
    at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
    at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
    at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
    at $Proxy9.deploy(Unknown Source)
    at org.jboss.deployment.scanner.URLDeploymentScanner.deploy(URLDeploymentScanner.java:421)
    at org.jboss.deployment.scanner.URLDeploymentScanner.scan(URLDeploymentScanner.java:610)
    at org.jboss.deployment.scanner.AbstractDeploymentScanner$ScannerThread.doScan(AbstractDeploymentScanner.java:263)
    at org.jboss.deployment.scanner.AbstractDeploymentScanner$ScannerThread.loop(AbstractDeploymentScanner.java:274)
    at org.jboss.deployment.scanner.AbstractDeploymentScanner$ScannerThread.run(AbstractDeploymentScanner.java:225)

    Khi Chạy với EE5 và GlassFishV3 thì không có lỗi gì xãy ra
    Mong anh chị, và thầy giúp.

  27. minhan said

    Cho em hỏi, em mới làm quen với jsp sử dụng server jboss và ide là netbean, nhưng khi lập trình và run web thì rất chậm (máy e cấu hình dua core 2.0 mà run gần 1 phút).Không biết đó có phải là lỗi cấu hình gì ko?Có cách nào run nhanh hơn không?

  28. metal said

    Nói thật là tôi chưa thấy ví dụ (EJB) nào anh trình bày chạy mà không báo lỗi cả.
    Thường những người mới bắt đầu tìm hiểu EJB mới tìm đọc những bài như thế này, nhưng tiếc là anh đăng bài như để thể hiện là anh đã làm việc với EJB. Mục đích anh viết bài là gì? Những bài này có phải dành cho newbie EJB ko?
    Nếu đã bỏ công viết thì hãy viết cho đâu ra đấy!
    Tôi chỉ muốn chạy thử ví dụ về EJB, tôi cảm thấy mất thời gian khi làm theo những bài anh viết!

    p/s: Lý do tôi hạn chế đọc tutorial hay ebook tiếng Việt là cũng vì thế, toàn thông tin cũ, thiếu chính xác và không rõ ràng.

    Xin lỗi nếu bài viết này làm anh không thỏa mái.

  29. Võ Văn Hải said

    Tất cả đều đảm bảo là đã được chạy trước khi đưa lên. Có lẽ bạn cấu hình thiếu hoặc có gì đó chưa ổn. rất cám ơn bạn đã thẳng thắng góp ý!

  30. Phuong Huynh said

    Hom nay toi google de resolve 1 problem cua SQL Express 2008 thi vo tinh thay tutorial na`y.
    JEE thi khong de dang deploy dau, phai “chi`” voi no thi may ra moi thanh cong dc, cac ban khong nen y kien phan bien nguoi viet bai.
    Rieng toi cam thay viec anh Hai chiu kho’ post tutorial bang Vietnamese la rat tot roi.
    Tien tay, toi co mot de xuat nho den anh Hai trong viec su dung maven de quan ly cac ung dung JEE.

    🙂

  31. kenz said

    javax.naming.NameNotFoundException: ProductBean not bound
    at org.jnp.server.NamingServer.getBinding(NamingServer.java:529)
    at org.jnp.server.NamingServer.getBinding(NamingServer.java:537)
    at org.jnp.server.NamingServer.getObject(NamingServer.java:543)
    at org.jnp.server.NamingServer.lookup(NamingServer.java:267)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
    at sun.rmi.transport.Transport$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)
    at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
    at sun.rmi.server.UnicastRef.invoke(Unknown Source)
    at org.jnp.server.NamingServer_Stub.lookup(Unknown Source)
    at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:625)
    at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:587)
    at javax.naming.InitialContext.lookup(Unknown Source)
    at com.example.entitybean.ProductClient.main(ProductClient.java:19)

    em chào Anh, em đã làm theo ví dụ của anh, và đã deploy được file EJB3_Entity_Products.jar
    nhưng khi chạy client thì xẩy ra lỗi ở trên.
    Vậy phải xử lý thế nào ạ

  32. Võ Văn Hải said

    Bạn triển khai phía server chưa được hoặc là tên của bean đã thay đổi. Kiểm tra lại 2 yếu tố này.

  33. Tri said

    Sinh viên xa nhà cần lắm những người thầy nhiệt tâm như bạn.Chúc bạn mỗi ngày đều hạnh phúc với niềm đam mê của mình nhé!

  34. duy khanh said

    em chào thầy!
    project của em dùng EJB3 + GlassFishv3 + Netbean
    Em tạo session bean Hello có phương thức sayHello();
    và trong file controller.java em khai báo @EJB để gọi bean này thì khi run project thì chạy ok!
    Em tạo tiếp entity bean Test kết nối tới 1 bảng trong csdl và trong file controller.java em khai báo thêm:
    @PersistenceUnit
    private EntityManagerFactory entitymanager;
    để thao tác với đối tượng entity bean, khi em run project thì sinh ra lỗi:
    Initial deploying EnterpriseApplication1 to C:\Users\ndkjava\Documents\NetBeansProjects\EnterpriseApplication1\dist\gfdeploy\EnterpriseApplication1
    Completed initial distribution of EnterpriseApplication1
    Initializing…
    deploy?DEFAULT=C:\Users\ndkjava\Documents\NetBeansProjects\EnterpriseApplication1\dist\gfdeploy\EnterpriseApplication1&name=EnterpriseApplication1&force=true failed on GlassFish Server 3.x
    Error occurred during deployment: Exception while preparing the app : Could not resolve a persistence unit corresponding to the persistence-unit-ref-name [controller.controller/entitymanager] in scope of the module called [EnterpriseApplication1#EnterpriseApplication1-war.war]. Please verify your application.. Please see server.log for more details.
    Exception while invoking class org.glassfish.persistence.jpa.JPADeployer prepare method : java.lang.RuntimeException: Could not resolve a persistence unit corresponding to the persistence-unit-ref-name [controller.controller/entitymanager] in scope of the module called [EnterpriseApplication1#EnterpriseApplication1-war.war]. Please verify your application.
    Could not resolve a persistence unit corresponding to the persistence-unit-ref-name [controller.controller/entitymanager] in scope of the module called [EnterpriseApplication1#EnterpriseApplication1-war.war]. Please verify your application.
    C:\Users\ndkjava\Documents\NetBeansProjects\EnterpriseApplication1\nbproject\build-impl.xml:284:
    The module has not been deployed.
    at org.netbeans.modules.j2ee.deployment.devmodules.api.Deployment.deploy(Deployment.java:187)
    at org.netbeans.modules.j2ee.ant.Deploy.execute(Deploy.java:106)
    at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
    at sun.reflect.GeneratedMethodAccessor880.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
    at org.apache.tools.ant.Task.perform(Task.java:348)
    at org.apache.tools.ant.Target.execute(Target.java:390)
    at org.apache.tools.ant.Target.performTasks(Target.java:411)
    at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1399)
    at org.apache.tools.ant.Project.executeTarget(Project.java:1368)
    at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
    at org.apache.tools.ant.Project.executeTargets(Project.java:1251)
    at org.apache.tools.ant.module.bridge.impl.BridgeImpl.run(BridgeImpl.java:284)
    at org.apache.tools.ant.module.run.TargetExecutor.run(TargetExecutor.java:539)
    at org.netbeans.core.execution.RunClassThread.run(RunClassThread.java:154)
    BUILD FAILED (total time: 1 second)
    Sau đó em bỏ dòng khai báo dùng enity bean:
    @PersistenceUnit
    private EntityManagerFactory entitymanager;
    thì không có lỗi trên nữa, nhưng chỉ dùng được session bean Hello.
    Vậy giờ làm sao để sửa lỗi trên ạ! em cảm ơn thầy.

  35. Võ Văn Hải said

    Em đảm bảo là app của em có persistent unit chưa? (trong EntityBean mà em gọi đảm bảo là được deploy đúng?)

  36. cong cong said

    Chào thầy,

    Em muốn dùng EJB để kết nối multiple database, nhưng trong file persistence.xml chỉ nhận đầu tiên mà không nhận các tiếp theo. Nhờ thầy chỉ dẫn cách để có thể kết nối multiple database giúp. Em cảm ơn thầy

  37. Nguyễn Chánh Tín said

    Thầy ơi cho em hỏi vì sao khi mỗi lần em run eproject thì trong tập tin deploy của jboss nó lại sinh ra file có dạng là
    jboss-ds.xml . làm cho file cấu hình không thể deploy len được .
    vậy thầy có cách nào chỉ cho em với. em nghe thầy Sơn nói xóa cái file shorcut gì đó thì khi run nó sẽ ko bị nữa ,mà em tìm hoài ko thấy .

  38. jboss-ds.xml là file data source để kết nối database. Bạn xóa cái file jboss-ds.xml trong thư mục deploy của jboss đi rồi copy cái file jboss-ds.xml mới của project thả vào thư mục deploy của jboss.

  39. hải said

    Em chào thầy!
    project của em chạy báo lỗi:
    12/07/22 02:20:00 Error initializing data-source ‘jdbc/hNMEACoreDS’: DriverManagerDataSource driver ‘org.hsql.jdbcDriver’ not found

    Embedded OC4J startup time: 1595 ms.
    Thầy cho em hỏi lỗi này là do đâu ạ? và em phải làm ntn để config nó?
    Em cảm ơn thầy!

  40. Nguyen Van nam said

    Anh em cho hỏi chút vì mình mới làm quen với Jboss, có cách nào để tạo Entity Bean theo kiểu no database, nghĩa là mình có thể switch qua các database(oracle, sqlserver, mysql)

    Cảm ơn nhiều 🙂

  41. Nguyễn Khắc Mạnh said

    Thầy ơi cho em hỏi cái này.em đọc được ` hướng dẫn tạo project JSF chạy trên nền JBoss, trên trang web khác nhưng em không tải được bản jboss về.Em thấy clip demo của thầy về cách tạo project JSF và có bước chọn thư viện jsf,jstl trong jboss 4.2.GA gì đấy (em quên rồi).những thư viện này chắc là trong file Jboss tải về hả thầy.(cái hướng dẫn đó bảo phải tải về jboss 4.2GA)Vì em không tải được jboss nên em đã cài nó = Eclipse marketplace rồi.Em đã mở được Jboss central nhưng không biết dùng,em thử tạo lại project khác nhưng nó vẫn cứ đòi thư viện jsf và jstl.Do eclipse indiago của em chỉ có javaserverface 2.0 nên e đã tải thứ viện jsf 2.0.Còn jstl thì là 1.2,không biết nó có tương ứng phiên bản với nhau không nữa. Vậy thì việc em cài Jboss từ Eclipse markerplace và việc phải tải nó về thì có khác nhau cho cách tạo project JSF không ạ..Em giờ đang rối lắm,không biết phải bắt đầu lại từ đâu.Mong thầy hướng dẫn giúp

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.