Home > Articles > Web Development

This chapter is from the book

Programming Model

OpenJPA is a persistence framework based around persisting common POJOs. It relies on Java Annotations and/or XML to add the persistence behavior. Both options are available. OpenJPA also provides a very rich Object Query Language, batch statement features, and other useful features. As a last resort, OpenJPA allows a developer to drop down to Native SQL.

The basic programming model is relatively straightforward, with an EntityManager (created using an EntityManagerFactory or injected by the environment such as an EJB 3 container) being used to establish a persistent session context in which Plain Old Java Objects (POJOs) can be moved in and out of a persistent context.

It is worth mentioning here that an object association with an EntityManager defines the state in which it is managed. Figure 8.1 illustrates the life cycle of a Java object with respect to persistence in OpenJPA.

Figure 8.1

Figure 8.1 OpenJPA life cycle management.

This life cycle is interesting because it brings together the notion of an EntityManager and a POJO, resulting in four states to consider in the programming model:

  • New/Transient—The Object is instantiated, but there is no relational data in the database.
  • Managed—The Object is associated with the persistent manager, and therefore the instance has a database record and the Java instance is connected to its record. Executing getters() and setters() imply database operations.
  • Detached—The EntityManager is closed but the instance is still around. It is just a Value Object at this point. Executing getters() and setters() do not imply database updates. You can move a detached instance back to a Managed state by calling merge on the EntityManager.
  • Removed—This is an instance that is no longer in the database because it has been deleted. After the transaction is committed, the object is just like any other transient Java Object.

Within this context, we will consider the specific details of how to do initialization, make connections, create transactions, invoke CRUD methods, and so on.

Initialization

The heart of persisting POJOs relies on a special object called an EntityManager. The goal for a developer is to initialize an EntityManager with the proper mappings and database information necessary. JPA provides several ways to load an EntityManager, depending on the environment.

To initialize the framework, you need to create a file called persistence.xml, as shown in Figure 8.1, and define a persistence unit, as shown in Listing 8.1. The listing contains the information necessary for a Java SE Application to configure a persistence unit.

Listing 8.1. Java SE Persistence Unit

<persistence-unit name="pie-db-JAVA-SE">
   <provider>
   org.apache.openjpa.persistence.PersistenceProviderImpl
   </provider>
   <properties>
      <property name="openjpa.ConnectionURL"
         value="jdbc:derby://localhost:1527/PWTE"/>
      <property name="openjpa.ConnectionDriverName"
         value="org.apache.derby.jdbc.ClientDriver"/>
      <property name="openjpa.jdbc.DBDictionary" value="derby"/>
      <property name="openjpa.Log"
         value="DefaultLevel=WARN,
         Runtime=INFO,
         Tool=INFO,
       SQL=TRACE"/>
      <property name="openjpa.jdbc.Schema" value="APP"/>
   </properties>
</persistence-unit>

The first thing you do is define your provider, which in this case is OpenJPA. Then you use the properties to set up the name of the Driver or DataSource implementation and any additional properties. A full list of properties can be found in the Open JPA Manual referenced earlier [OpenJPA 2l].

In a Java EE environment, the configuration will be slightly different. Application Servers, like WebSphere Application Server, will often provide a default JPA implementation, and it is therefore not necessary to provide a JPA provider. Listing 8.2 shows an example of a persistence.xml file in a Java EE environment. In it, you can provide the JNDI name of a configured DataSource. The DataSource implementation is vendor specific. Some Application Server vendors allow for swapping the default implementation.

Listing 8.2. Java EE Persistence Unit

<persistence-unit name="pie-db-JAVA-EE">
    <jta-data-source>jdbc/orderds</jta-data-source>
    <properties>
        <property name="openjpa.jdbc.DBDictionary" value="derby"/>
        <property name="openjpa.jdbc.Schema" value="APP"/>
    </properties>
</persistence-unit>

Connections

After you configure the persistence unit, JPA will have the necessary information to instantiate a persistence context. A persistence context is a set of managed entity instances in which, for any persistent entity identity, there is a unique entity instance. Within the persistence context, the entity's association with the underlying persistence store is managed by the EntityManager (EM). If you are familiar with Hibernate, the EntityManager is similar to the Hibernate Session.

All the connections to the underlying database are encapsulated within the EM. So getting an instance of the EntityManager will get a connection for you as needed without any explicit coding on your part. However, getting an instance of the EntityManager varies between a Java SE and Java EE environment. In a Java SE environment, an application-managed EM instance is created by calling the EntityManagerFactory, and the lifetime of that instance is controlled by the application. For each application-managed EM instance, there are one or more corresponding application-managed persistence contexts, which are not linked with any transaction and are not propagated to other components. It is important to realize that you must open and close the Entity Manager yourself in an application coded to run in a Java SE environment.

The Persistence class is used as a bootstrap to get access to an EntityManagerFactory for a particular persistence unit configured in a Java SE environment. After you get access to the EntityManagerFactory, you can use that to get an instance of an EntityManager that can be used throughout your code to implement the persistence code. Listing 8.3 shows an example of this process. In this code, we illustrate the three steps just discussed. Notice that in this example, the EntityManager is scoped to each business method. This is one common pattern in a Java SE environment.

Listing 8.3. Look Up Entity Manager Factory

public class CustomerOrderServicesJavaSEImpl{
    protected EntityManagerFactory emf  =
        Persistence.createEntityManagerFactory(
        "pie-db-JAVA-SE"
    
    );
    public Order openOrder(int customerId)throws Exception {
        EntityManager em = emf.createEntityManager();
        em = emf.createEntityManager();
        //Code
        em.close();
    }
...
}

It is worth noting that opening and closing an Entity Manager may be slower than keeping an instance around in some scenarios.

In a Java EE environment, the container can "inject" an EntityManagerFactory into a Java EE artifact, such as a Stateless Session Bean or an HttpServlet. Listing 8.4 shows an example of injecting an EntityManagerFactory into a Stateless Session Bean. Once injected, it is used the same way we illustrated earlier. Notice that you still must programmatically close the EntityManager because you used a factory to create the EntityManager. This is because you are still using an application-managed EntityManager.

Listing 8.4. Inject Entity Manager Factory

@Stateless
public class CustomerOrderServices {
    @PersistenceUnit (unitName = "pie-db-JAVA-EE")
    protected EntityManagerFactory emf;
    public Order openOrder(int customerId)throws Exception
    {
        EntityManager em = emf.createEntityManager();
        //Code
        em.close();
    }
...
}

In an EJB 3 environment, a container-managed EM instance is created by directing the container to inject one instance (either through direct injection or through JNDI lookup). The lifetime of that EM instance is controlled by the container; the instance matches the lifetime of the component into which it was injected. Container-managed Entity Managers will also provide automatic propagation of transactions, connections, and other services. We will discuss this further after transactions are discussed.

An EntityManager can be injected directly into an EJB, using a Java annotation called PersistenceContext. Listing 8.5 shows an example of this. In this case, the developer does not have to worry about a factory. Furthermore, you delegate to the container the management of the EntityManager and the propagation of the proper persistence context from EJB component to EJB component. This is a more common pattern in Java EE. If you are using the PersistenceContext in an EJB 3 component, the EJB 3 container will automatically propagate the persistence context for a particular request across components. It is important to keep in mind that an EJB 3 Session Bean is a thread-safe component, and therefore, only one client request is being serviced by the EJB component at a time. This means the EntityManager can safely be used by the instance without fear of another thread accessing it. The container can also take advantage of this and pass the current persistence context which can contain an active transaction.

Listing 8.5. Inject EntityManager

@Stateless
public class CustomerOrderServices {
    @PersistenceContext (unitName = "pie-db-JAVA-EE") //Step 1
    protected EntityManager em;

To illustrate the object states shown in Figure 8.1 in context of the code to get access to the EntityManager, see Listing 8.6. This listing shows objects in various states and how they move from one state to another. The comments within the listing describe the action.

Listing 8.6. Object States

//Set up EM and Transient POJO instance
em = emf.createEntityManager();
Order newOrder = new Order();
newOrder.setStatus(Order.Status.OPEN);
newOrder.setTotal(new BigDecimal(0));

//Make POJO Managed by persisting it
em.persist(newOrder);
newOrder.setTotal(new BigDecimal(1));

//Make POJO Detached by closing
em.close();
newOrder.setTotal(new BigDecimal(2));

//Make POJO Managed by merging detached instance
em2 = emf.createEntityManager();
em2.merge(newOrder;)

As long as a POJO is associated with an EntityManager, updates to the database are implied and the instance is managed. Managed Entities are either (a) loaded by the EntityManager via a find method or query, or (b) associated with the EntityManager with a persist or merge operation. We discuss this more in later sections on the Create, Retrieve, Update, and Destroy operations.

Transactions

You can demarcate transactions in OpenJPA in the following ways:

  • Using a standard programmatic API such as the JTA interfaces
  • Using the special javax.persistence.EntityTransaction interface provided by JPA
  • Using declarative transactions within an EJB 3 Container

We have covered JDBC and JTA transactions in previous chapters. Listing 8.7 shows an example of using the EntityTransaction interface. A developer can get an instance of an EntityTransaction by calling getTransaction() on the EntityManager. After they have an instance, you can call begin, commit, or rollback. This is often the norm when using OpenJPA in a Java SE environment or in the web container.

Listing 8.7. Entity Manager Transaction Demarcation

public Order openOrder(int customerId)
throws CustomerDoesNotExistException,
       OrderAlreadyOpenException,
       GeneralPersistenceException {
    EntityManager em = null;
    try {
        em = emf.createEntityManager();
        em.getTransaction().begin();
        //use em to manage objects
        em.getTransaction().commit();
        return newOrder;
    }
    catch(CustomerDoesNotExistException e){
        em.getTransaction().rollback();
        throw e;
    }
    //Handle other Exceptions not listed
    finally {
        if (em != null) em.close();
    }
}

If a developer uses an external API like JTA to demarcate transactions and you are using an application-managed EntityManager, you need to have your EntityManager instance "join" the transaction. Listing 8.8 illustrates this situation and shows the code needed to cause the join.

Listing 8.8. Join Transaction

@PersistenceUnit (unitName = "pie-db-JAVA-EE")
protected EntityManagerFactory emf;

public Order openOrder(int customerId)throws Exception {
    javax.transaction.UserTransaction tran =
        //code to lookup UserTransaction in JNDI

    EntityManager em = emf.createEntityManager();
    try {
        // Start JTA transaction
        tran.begin();

        // Have em explicitly join it
        em = emf.createEntityManager();
        em.joinTransaction();

        //Code in transaction scope ready to commit
        tran.commit();

        //Code outside of transaction scope
    }
    catch(Exception e) {
        tran.rollback();
        throw e;
    }
    finally {
        em.close();
    }
}

When OpenJPA is used in an EJB 3 container, OpenJPA will allow for transactions to be controlled by EJB transaction demarcation. Listing 8.9 shows an example of JPA being used within an EJB 3 Session Bean. The EJB 3 method is marked with a Required transaction. In addition, the EntityManager is injected into the EJB 3 POJO. In this scenario, you get the benefit of having the container manage the EntityManager for you using the container-managed Entity Manager discussed in the preceding section.

Listing 8.9. EJB 3 Transaction Demarcation

@Stateless
public class CustomerOrderServicesImpl implements CustomerOrderServices
{
    @PersistenceContext(unitName="pie-db-JAVA-EE")
    protected EntityManager em;

    @TransactionAttribute(value=TransactionAttributeType.REQUIRED)
    public Order openOrder(int customerId)
    throws CustomerDoesNotExistException,
           OrderAlreadyOpenException,
           GeneralPersistenceException {
        // use em
    }

For each container-managed EM instance, there are one or more corresponding container-managed persistence contexts (PCs). At the time the PC is created, it is linked with the transaction currently in effect and propagated by the container, along with the transaction context to other called components within the same JVM.

The container-managed usage scenario is further subcategorized into transaction-scoped (lifetime is controlled by the transaction) and extended (lifetime is controlled by one or more stateful session bean instances). This means that in the transaction case, inside an EJB 3 container, the persistence context life cycle is governed by the transaction. You get automatic flushing of cache at the end of the transaction. JPA also provides an extended PersistenceContext that will be managed by some greater scope, such as a Stateful Session Bean or perhaps an Http Session. Listing 8.10 shows how you can inject a longer-lived Persistence Context.

Listing 8.10. Extended Persistence Context

@PersistenceContext(
    unitName="pie-db-JAVAEE", type=PersistenceContextType.EXTENDED
)
protected EntityManager em;

In Chapter 5, "JDBC," we discussed savepoints. Savepoints allow for fine-grained control over the transactional behavior of your application. The JPA specification does not allow for savepoints; however, some vendors, like OpenJPA, may have extensions. OpenJPA's savepoint API allows you to set intermediate rollback points in your transaction. You can then choose to roll back changes made only after a specific savepoint, then commit or continue making new changes in the transaction. OpenJPA's OpenJPAEntityManager (subtype of JPA's EntityManager) supports these savepoint operations:

  • void setSavepoint(String name);
  • void releaseSavepoint(String name);
  • void rollbackToSavepoint(String name);

Savepoints require some configuration, so refer to the OpenJPA documentation for more details.

Create

The EntityManager has most of the methods needed to persist Java objects, or entities. Persistence actions usually occur by passing instances of entities to and from the EntityManager. So for creating data, you would just create an instance of an entity and persist it using the persist method of the EntityManager. Listing 8.11 shows an example of this.

Listing 8.11. Persist Data

Order newOrder = new Order();
newOrder.setCustomer(customer);
newOrder.setStatus(Order.Status.OPEN);
newOrder.setTotal(new BigDecimal(0));
em.persist(newOrder);

This will correspond to an INSERT into the database. The Order object in the example is mapped to a table in the database. A POJO mapped to a database is called an Entity in JPA. We will discuss mappings in the "ORM Features Supported" section.

Retrieve

Reading data can be done several ways. The simplest read is to read an object by primary key. The EntityManager find method provides an easy way to do this. Listing 8.12 illustrates this. The find method takes the name of the class and a primary key value as a parameter. We discuss mapping primary keys in the later section, "ORM Features Supported."

Listing 8.12. Finding Entity Instances

AbstractCustomer customer = em.find(AbstractCustomer.class, customerId);

Using the find methods, OpenJPA can load a whole Object Graph. Listing 8.13 shows an example of accessing the Order Object after loading the customer. If the Order Object is mapped as a relationship and the proper fetching strategies are set, OpenJPA will load more than the root object with the find method. Later in the chapter, fetching is discussed.

Listing 8.13. Related Entity Instances

AbstractCustomer customer = em.find(AbstractCustomer.class, customerId);
Order existingOpenOrder = customer.getOpenOrder();

JPA also comes with a rich query language called EJB-QL (sometimes called JPQL). You can issue queries against the object model. We will not provide a detailed tutorial on the query languages, and instead recommend that you read the reference guide [JPQL]; but the query language provides syntax to execute complex queries against related objects. Listing 8.14 shows an example of executing a query. As a developer, you can create a query using the createQuery against the EntityManager. Notice you can use :name to mark places where you want to use parameters. OpenJPA also supports using the ? approach used by JDBC Prepared Statements. However, both approaches will translate to Prepared Statements.

Listing 8.14. Executing JPA Queries

Query query = em.createQuery(
    "select l from LineItem l
     where l.productId = :productId and l.orderId = :orderId "
);
query.setParameter("productId", productId);
query.setParameter("orderId", existingOpenOrder.getOrderId());
LineItem item = (LineItem) query.getSingleResult();

OpenJPA also supports the capability to externalize queries from the code using the "named query" concept, which allows you to associate a query to a name using an annotation or the XML mapping file. Listing 8.13 shows how you annotate a POJO with the NamedQuery. The rest of the annotations in the listing are explained in the later section, "ORM Features Supported." After you define the NamedQuery, you can execute somewhere else in your code, as shown in the second part of Listing 8.15. It is worth mentioning that if you want to truly externalize the queries, you should use the XML deployment descriptor.

Listing 8.15. Executing JPA Queries

@Entity
@Table(name="LINE_ITEM")
@IdClass(LineItemId.class)
@NamedQuery(
    name="existing.lineitem.forproduct",
    query="
        select l from LineItem l
        where l.productId = :productId
        and l.orderId = :orderId"
)
public class LineItem {
    ...
    Query query = em.createNamedQuery("existing.lineitem.forproduct");
    query.setParameter("productId", productId);
    query.setParameter("orderId", existingOpenOrder.getOrderId());
    LineItem item = (LineItem) query.getSingleResult();

With EJB-QL, when you are querying for Objects, you can load related objects as well, depending on the mapping. You can also load objects using joins. OpenJPA also extends EJB-QL with some value adds.

For the majority of the cases, you should be able to get data you need. There are cases when you need to drop down to native SQL. This could be to call a Stored Procedure, to get an optimized SQL, or because you cannot get OpenJPA to generate the correct SQL needed for the use case. OpenJPA supports the notion of native queries. You can execute SQL and project onto a POJO. An example is shown in Listing 8.16.

Listing 8.16. Native SQL

Query query = em.createNativeQuery(
    "SELECT * FROM LINE_ITEM", LineItem.class
);
List<LineItem> items = query.getResultList());

You can also have Native Named Queries if you want to externalize the SQL.

Update

OpenJPA supports updating existing data in a few ways. Figure 8.1 showed you the life cycle of a POJO with respect to the EntityManager. Any field updated on a POJO that is associated with the EntityManager implies a database update. Listing 8.17 shows an example of code finding an instance of LineItem and executing an update.

Listing 8.17. Updating Persistent Entities

LineItem existingLineItem = em.find(LineItem.class,lineItemId);
existingLineItem.setQuantity(existingLineItem.getQuantity() + quantity);
existingLineItem.setAmount(existingLineItem.getAmount().add(amount));

Any update to related objects also implies an update. In Listing 8.18, we show that after finding the customer Entity, you can traverse to the Order. Because the customer is still being managed by the EntityManager, so is the Order.

Listing 8.18. Updating Related Entities

AbstractCustomer customer = em.find(AbstractCustomer.class, customerId);
Order existingOpenOrder = customer.getOpenOrder();
BigDecimal amount = product.getPrice().multiply(new BigDecimal(quantity));
existingOpenOrder.setTotal(amount.add(existingOpenOrder.getTotal()));

OpenJPA also supports updating of detached Entities using the merge method. Listing 8.19 shows an example of a detached case. In the first part of the listing, you can see a fragment of Servlet code calling a service. The Service implementation is shown in the second part of the listing. A web request first reads the data using an HTTP GET, which gets access to the data and stores it in sessions. The service implementation uses a find to access the data and finish the request. Then an HTTP POST comes in to update the data in session. The Servlet doPost passes the detached instance into the updateLineItem method. The implementation of updateLineItem will attempt to merge the instance to the EntityManager.

Listing 8.19. Updating via merging

public void doGet(
    HttpServletRequest request, HttpServletResponse response)
{
    String customerId = populateFromRequest(request);
    LineItem li = customerService.getLineItem(li);
    writeToSession(li);
}

public void doPost(
    HttpServletRequest request, HttpServletResponse response
)
{
    LineItem li = populateFromSession(request);
    customerService.updateLineItem(li);
}
...

public LineItem getLineItem(int liId) throws GeneralPersistenceException
{
    EntityManager em = //Get Entity Manager
    LineItem li  = emf.find(LineItem.class,liId);
    return li;
}

public void updateLineItem(LineItem li) throws GeneralPersistenceException {
    EntityManager em = //Get Entity Manager
    em.merge(li);
}

OpenJPA allows you to use EJB-QL to issue updates as well, such as shown in Listing 8.20. This feature enables you to update many instances with one statement. You also avoid hydrating objects in certain scenarios where performance is important.

Listing 8.20. Updating via Query Language

Query query = em.createQuery(
    "UPDATE CUSTOMER c
     SET o.discount = :discount
     WHERE c.type = 'RESIDENTIAL'"
);
query.setParameter("discount", discount);
query.executeUpdate();

Delete

You can delete data several ways using OpenJPA. A managed instance can be removed by calling remove on the EntityManager, as shown in Listing 8.21. (Listing 8.23 shows an even better option.)

Listing 8.21. Deleting via EntityManager Remove

LineItem existingLineItem = em.find(LineItem.class,lineItemId);
if(existingLineItem != null){
    em.remove(existingLineItem);
}

You can configure OpenJPA to propagate deletes along an object graph. We will show you mapping relationships later; however, in Listing 8.22, you can see that Order has a relationship to a Set of LineItem instances. On the relationship, you can see that we have set the cascade to REMOVE. This means that when you delete an Order, all associated Lineitem instances will be deleted as well.

Listing 8.22. Deleting via Cascading

@Entity
@Table(name="ORDERS")

public class Order implements Serializable {
    ...
    @OneToMany(cascade=CascadeType.REMOVE, fetch=FetchType.EAGER )
    @ElementJoinColumn(
        name="ORDER_ID",referencedColumnName="ORDER_ID"
    )
    protected Set<LineItem> lineitems;

Finally, much as with Updates, OpenJPA allows you to delete, using EJB-QL Queries. Listing 8.23 shows an example of deleting via a query. This approach is useful if you want to delete many rows with one network call.

Listing 8.23. Deleting via a Query

Query query = em.createQuery(
    "DELETE FROM LineItem l
     WHERE l.productId = :productId
     and l.orderId = :orderId"
);
query.setParameter("productId", productId);
query.setParameter("orderId", existingOpenOrder.getOrderId());
query.executeUpdate();

Stored Procedures

We already showed how you can use native queries in OpenJPA. Native queries can be used to call stored procedures as shown in Listing 8.24.

Listing 8.24. Using a Native Query to Call a Stored Procedure

Query query = em.createNativeQuery("CALL SHIP_ORDER(?)");
query.setParameter(1, orderId);
query.executeUpdate());

Batch Operations

As we showed in the Update and Delete sections, OpenJPA supports batching updates and deletes using EJB-QL. The Apache version of OpenJPA (1.0.0) currently does not support automatic statement batching for persistent operations. However, vendors that build on top of OpenJPA sometimes provide this function. The EJB 3 implementation of WebSphere Application Server provides an enhanced version of OpenJPA. They provide a configuration option for deferring update operations to commit time and batching them together. Other vendors may provide similar optimizations. The optimizations can make mass updates several orders of magnitude faster; see also the "Batch Operations" section in Chapter 5 for details of how this approach works.

Extending the Framework

When writing OpenJPA plug-ins or otherwise extending the OpenJPA runtime, however, you will use OpenJPA's native APIs. OpenJPA allows you to extend the framework in various ways, including these:

  • You can extend the default EntityManager or EntityManagerFactory. This is often done by Vendors offering enhanced JPA implementations on top of OpenJPA.
  • You can extend the query engine. This is usually done to provide optimized solutions, such as integrating with cache technologies.
  • Data Caches can be added to back the OpenJPA cache.
  • Other areas support extending behavior, such as fetch and primary key generation strategies.

The OpenJPA implementation shows the specific interfaces and classes that need to be extended to provide your own extensions.

Error Handling

JPA Exceptions are unchecked. Figure 8.2 shows the JPA Exception Architecture. JPA uses standard exceptions where appropriate, most notably IllegalArgumentExceptions and IllegalStateExceptions. These exceptions can occur when you perform persistence actions without the proper setup—for example, sending an Entity to an EntityManager that is not managing it.

Figure 8.2

Figure 8.2 JPA exception class diagram.

The specification also provides a few JPA-specific exceptions in the javax.persistence package. Listing 8.25 shows an example of catching an EntityNotFoundException. Alternatively, because the exceptions are unchecked, you can choose to not catch it and handle it at a higher level.

Listing 8.25. Exception Example

{   try
    AbstractCustomer customer = em.find(
        AbstractCustomer.class, customerId
    );
    ...
}
catch(javax.persistence.EntityNotFoundException e)
{    throw new GeneralPersistenceException(e);

}

All exceptions thrown by OpenJPA implement org.apache.openjpa.util.Exception Info to provide you with additional error information. Figure 8.3 shows the class diagram of the ExceptionInfo interface.

Figure 8.3

Figure 8.3 ExceptionInfo interface.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020