You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pp...@apache.org on 2010/05/14 04:14:32 UTC

svn commit: r944083 [4/4] - in /openjpa/trunk/openjpa-examples/openbooks/src: ./ main/ main/java/ main/java/jpa/ main/java/jpa/tools/ main/java/jpa/tools/swing/ main/java/openbook/ main/java/openbook/client/ main/java/openbook/domain/ main/java/openboo...

Added: openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/OpenBookServiceImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/OpenBookServiceImpl.java?rev=944083&view=auto
==============================================================================
--- openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/OpenBookServiceImpl.java (added)
+++ openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/OpenBookServiceImpl.java Fri May 14 02:14:30 2010
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2010 Pinaki Poddar
+ *
+ *  Licensed 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.
+*/
+package openbook.server;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceContextType;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Expression;
+import javax.persistence.criteria.ParameterExpression;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import javax.persistence.metamodel.EntityType;
+
+import openbook.domain.Author;
+import openbook.domain.Author_;
+import openbook.domain.Book;
+import openbook.domain.Book_;
+import openbook.domain.Customer;
+import openbook.domain.Customer_;
+import openbook.domain.Inventory;
+import openbook.domain.Inventory_;
+import openbook.domain.LineItem;
+import openbook.domain.PurchaseOrder;
+import openbook.domain.PurchaseOrder_;
+import openbook.domain.Range;
+import openbook.domain.ShoppingCart;
+import openbook.util.PropertyHelper;
+import openbook.util.Randomizer;
+
+import org.apache.openjpa.persistence.criteria.OpenJPACriteriaBuilder;
+
+/**
+ * A demonstrative example of a transaction service with persistent entity using Java Persistence API.
+ * <br>
+ * This example service operates on a persistent domain model to browse {@linkplain Book books}, 
+ * occasionally {@linkplain #placeOrder(ShoppingCart) placing} {@linkplain PurchaseOrder purchase orders}, 
+ * while {@linkplain Inventory inventory} gets updated either by {@linkplain #deliver() delivery} or 
+ * by {@linkplain #supply() supply}. 
+ * <br>
+ * The operational model as well as the persistent domain model is influenced by the fact that
+ * a JPA based application can benefit from  
+ * <LI>Mostly Immutable Persistent Data Model
+ * <LI>Optimistic Transaction Model 
+ * <br>for better scalability and throughput.
+ * <br>  
+ *  
+ * @author Pinaki Poddar
+ *
+ */
+@SuppressWarnings("serial")
+class OpenBookServiceImpl extends PersistenceService implements OpenBookService {
+    
+    public static final int   CUSTOMER_COUNT     = 10;
+    public static final int   BOOK_COUNT         = 100;
+    public static final int   AUTHOR_COUNT       = 40;
+    public static final int   AUTHOR_PER_BOOK    = 3;
+    
+    /**
+     * Range of number of queries executed for a {@linkplain #shop() shopping} trip.
+     */
+    public static final Range<Double> PRICE_RANGE  = new Range<Double>(4.99, 120.99);
+    public static final Range<Integer> STOCK_RANGE = new Range<Integer>(5, 50);
+    public static final int REORDER_LEVEL          = 10;
+    
+    OpenBookServiceImpl(String unit, EntityManagerFactory emf, boolean managed,
+            PersistenceContextType scope) {
+        super(unit, emf, managed, scope);
+    }
+    
+    /**
+     * Initialize service by populating inventory of Books and Customers.
+     * If the inventory exists, then returns immediately without creating any new inventory.
+     * 
+     * @return true if new inventory is created. false otherwise.
+     */
+    public boolean initialize(Map<String,Object> config) {
+        if (isInitialized()) {
+            return false;
+        }
+        EntityManager em = begin();
+        if (config == null) {
+            config = Collections.EMPTY_MAP;
+        }
+        int nCustomer  = PropertyHelper.getInteger(config, "openbook.Customer.Count",  CUSTOMER_COUNT);
+        int nBook   = PropertyHelper.getInteger(config, "openbook.Book.Count",  BOOK_COUNT);
+        int nAuthor = PropertyHelper.getInteger(config, "openbook.Author.Count",  AUTHOR_COUNT);
+        int nAuthorPerBook = PropertyHelper.getInteger(config, "openbook.Book.Author.Count", AUTHOR_PER_BOOK);
+
+        Double priceMax = PropertyHelper.getDouble(config, "openbook.Book.Price.Max",  PRICE_RANGE.getMaximum());
+        Double priceMin = PropertyHelper.getDouble(config, "openbook.Book.Price.Min",  PRICE_RANGE.getMinimum());
+
+        Integer stockMax = PropertyHelper.getInteger(config, "openbook.Inventory.Max", STOCK_RANGE.getMaximum());
+        Integer stockMin = PropertyHelper.getInteger(config, "openbook.Inventory.Min", STOCK_RANGE.getMinimum());
+        
+        System.err.println("Creating " + nCustomer + " new Customer");
+        for (int i = 1; i < nCustomer; i++) {
+            Customer customer = new Customer();
+            customer.setName("Customer-"+i);
+            em.persist(customer);
+        }
+
+        List<Author> allAuthors = new ArrayList<Author>();
+        System.err.println("Creating " + nAuthor + " new Authors");
+        for (int i = 1; i <= nAuthor; i++) {
+            Author author = new Author();
+            author.setName("Author-"+i);
+            allAuthors.add(author);
+            em.persist(author);
+        }
+        System.err.println("Creating " + nBook + " new Books");
+        System.err.println("Linking at most " + nAuthorPerBook + " Authors per Book");
+        for (int i = 1; i <= nBook; i++) {
+            Book book = new Book(Randomizer.randomString(4,2), 
+                                 "Book-" + i, 
+                                 Randomizer.random(priceMin, priceMax), 
+                                 Randomizer.random(stockMin, stockMax));
+            List<Author> authors = Randomizer.selectRandom(allAuthors, 
+                    Math.max(1, Randomizer.random(nAuthorPerBook)));
+            for (Author author : authors) {
+                author.addBook(book);
+                book.addAuthor(author);
+            }
+            em.persist(book);
+        }
+        
+        
+        commit();
+        return true;
+    }
+    
+    /**
+     * Affirms whether the database is loaded with some records.
+     */
+    public boolean isInitialized() {
+        return count(Book.class) > 0;
+    }
+    
+    /**
+     * Provide a name and email to login a Customer.
+     * If such a customer exists, return it. Otherwise creates a new one.
+     * @param name
+     * @return
+     */
+    public Customer login(String name) {
+        EntityManager em = begin();
+        
+        CriteriaBuilder cb = em.getCriteriaBuilder();
+        CriteriaQuery<Customer> q = cb.createQuery(Customer.class);
+        Customer customer = null;
+        Root<Customer> root = q.from(Customer.class);
+        ParameterExpression<String> pName = cb.parameter(String.class);
+        q.where(cb.equal(root.get(Customer_.name), pName));
+        List<Customer> customers = em.createQuery(q)
+          .setParameter(pName, name)
+          .getResultList();
+        if (customers.isEmpty()) {
+            Customer newCustomer = new Customer();
+            newCustomer.setName(name);
+            em.persist(newCustomer);
+            customer = newCustomer;
+        } else {
+            customer = customers.get(0);
+        }
+        commit();
+        return customer;
+    }
+    
+    /**
+     * Find books that match title and price range.
+     * @param title
+     * @param minPrice
+     * @param maxPrice
+     * @param author
+     * @return
+     */
+    
+    public List<Book> select(String title, Double minPrice, Double maxPrice, String author, 
+            QueryDecorator...decorators) {
+        CriteriaQuery<Book> q = buildQuery(title, minPrice, maxPrice, author);
+        EntityManager em = begin();
+        TypedQuery<Book> query = em.createQuery(q);
+        List<Book> result = query.getResultList();
+        commit();
+        return result;
+    }
+    
+    public String getQuery(String title, Double minPrice, Double maxPrice, String author) {
+        CriteriaQuery<Book> q = buildQuery(title, minPrice, maxPrice, author);
+        return q.toString();
+    }
+   
+    /**
+     * Creates a Query based on the values of the user input form. 
+     * The user may or may not have filled a value for each form field
+     * and accordingly the query will be different.<br>
+     * This is typical of a form-based query. To account for all possible
+     * combinations of field values to build a String-based JPQL can be
+     * a daunting exercise. This method demonstrates how such dynamic,
+     * conditional be alternatively developed using {@link CriteriaQuery}
+     * introduced in JPA version 2.0.
+     * <br>
+     * 
+     * 
+     * @return a typed query
+     */
+
+    private CriteriaQuery<Book> buildQuery(String title, 
+            Double minPrice, Double maxPrice, 
+            String author) {
+        CriteriaBuilder cb = getUnit().getCriteriaBuilder();
+        CriteriaQuery<Book> q = cb.createQuery(Book.class);
+        Root<Book> book = q.from(Book.class);
+        List<Predicate> predicates = new ArrayList<Predicate>();
+        if (title != null && title.trim().length() > 0) {
+            Predicate matchTitle = cb.like(book.get(Book_.title), title);
+            predicates.add(matchTitle);
+        }
+        if (minPrice != null && maxPrice != null) {
+            Predicate matchPrice = cb.between(book.get(Book_.price), minPrice, maxPrice);
+            predicates.add(matchPrice);
+        } else if (minPrice != null && maxPrice == null) {
+            Predicate matchPrice = cb.ge(book.get(Book_.price), minPrice);
+            predicates.add(matchPrice);
+        } else if (minPrice == null && maxPrice != null) {
+            Predicate matchPrice = cb.le(book.get(Book_.price), maxPrice);
+            predicates.add(matchPrice);
+        }
+        if (author != null && author.trim().length() > 0) {
+            Predicate matchAuthor = cb.like(book.join(Book_.authors).get(Author_.name), "%"+author+"%");
+            predicates.add(matchAuthor);
+        }
+            
+        q.select(book);
+        if (!predicates.isEmpty())
+            q.where(predicates.toArray(new Predicate[predicates.size()]));
+        
+        return q;
+    }
+
+    
+    /**
+     * Deliver pending orders.
+     * Queries for pending PurchaseOrders and attempts to deliver each in a separate
+     * transaction. Some of the transactions may fail because of concurrent modification
+     * on the inventory by the supplier.
+     */
+    public PurchaseOrder deliver(PurchaseOrder o) {
+        EntityManager em = begin();
+        o = em.merge(o);
+        o.setDelivered();
+        for (LineItem item : o.getItems()) {
+            item.getBook().getInventory().decrement(item.getQuantity());
+        }
+        commit();
+        return o;
+    }
+    
+    public List<PurchaseOrder> getOrders(PurchaseOrder.Status status) {
+        EntityManager em = begin();
+        CriteriaBuilder cb = em.getCriteriaBuilder();
+        CriteriaQuery<PurchaseOrder> q = cb.createQuery(PurchaseOrder.class);
+        Root<PurchaseOrder> order = q.from(PurchaseOrder.class);
+        q.select(order);
+        if (status != null) {
+            q.where(cb.equal(order.get(PurchaseOrder_.status), status));
+        }
+        q.orderBy(cb.desc(order.get(PurchaseOrder_.placedOn)));
+        
+        TypedQuery<PurchaseOrder> query = em.createQuery(q);
+        List<PurchaseOrder> result = query.getResultList();
+        commit();
+        return result;
+    }
+    
+    /**
+     * Creates a new {@linkplain PurchaseOrder} from the content of the given {@linkplain ShoppingCart}.
+     * <br>
+     * The transaction is not expected to fail because the inventory is
+     * not modified by placing an order.
+     * 
+     * @param cart a non-null Shopping cart.
+     */
+    public PurchaseOrder placeOrder(ShoppingCart cart) {
+        EntityManager em = begin();
+        PurchaseOrder order = new PurchaseOrder(cart);
+        em.persist(order);
+        commit();
+        return order;
+    }
+    
+    /**
+     * Supply books that have low inventory.
+     * <br>
+     * Queries for books with low inventory and supply each book in separate
+     * transaction. Some of the transactions may fail due to concurrent modification on
+     * the {@linkplain Inventory} by the {@linkplain #deliver() delivery} process. 
+     */
+    public Book supply(Book b, int quantity) {
+        EntityManager em = begin();
+        b = em.merge(b);
+        b.getInventory().increment(quantity);
+        commit();
+        return b;
+    }
+    
+    public List<Inventory> getReorderableBooks(int limit) {
+        EntityManager em = begin();
+        CriteriaBuilder cb = em.getCriteriaBuilder();
+        CriteriaQuery<Inventory> q = cb.createQuery(Inventory.class);
+        Root<Inventory> inv = q.from(Inventory.class);
+        q.select(inv);
+        Expression<Integer> inStock = cb.diff(
+                inv.get(Inventory_.supplied), 
+                inv.get(Inventory_.sold));
+        q.orderBy(cb.asc(inStock));
+        
+        List<Inventory> result = em.createQuery(q)
+                                   .setMaxResults(limit)
+                                   .getResultList();
+        commit();
+        return result;
+    }
+    
+    public long count(Class<?> cls) {
+        EntityManager em = getEntityManager();
+        CriteriaBuilder cb = em.getCriteriaBuilder();
+        CriteriaQuery<Long> c = cb.createQuery(Long.class);
+        Root<?> from = c.from(cls);
+        c.select(cb.count(from));
+        return em.createQuery(c).getSingleResult();
+    }
+    
+    public List<Book> selectByExample(Book b, QueryDecorator...decorators) {
+        return queryByTemplate(Book.class, b);
+    }
+    
+    private <T> List<T> queryByTemplate(Class<T> type, T template) {
+        EntityManager em = begin();
+        CriteriaBuilder cb = em.getCriteriaBuilder();
+        CriteriaQuery<T> c = cb.createQuery(type);
+        c.where(((OpenJPACriteriaBuilder)cb).qbe(c.from(type), template));
+        List<T> result = em.createQuery(c).getResultList();
+        commit();
+        return result;
+    }
+    
+    public <T> List<T> getExtent(Class<T> entityClass) {
+        EntityManager em = begin();
+        CriteriaQuery<T> c = em.getCriteriaBuilder().createQuery(entityClass);
+        c.from(entityClass);
+        List<T> result =  em.createQuery(c).getResultList();
+        commit();
+        return result;
+    }
+    
+    public <T> List<T> query(String jpql, Class<T> resultClass, QueryDecorator... decorators) {
+        EntityManager em = begin();
+        TypedQuery<T> query = em.createQuery(jpql, resultClass);
+        if (decorators != null) {
+            for (QueryDecorator decorator : decorators) {
+                decorator.decorate(query);
+            }
+        }
+        List<T> result =   query.getResultList();
+        commit();
+        return result;
+    }
+    
+    public void clean() {
+        EntityManager em = begin();
+        Set<EntityType<?>> entities = em.getMetamodel().getEntities();
+        for (EntityType<?> type : entities) {
+            System.err.println("Deleting all instances of " + type.getName());
+            em.createQuery("delete from " + type.getName() + " p").executeUpdate();
+        }
+        commit();
+    }
+
+
+}

Propchange: openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/OpenBookServiceImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/PersistenceService.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/PersistenceService.java?rev=944083&view=auto
==============================================================================
--- openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/PersistenceService.java (added)
+++ openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/PersistenceService.java Fri May 14 02:14:30 2010
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2010 Pinaki Poddar
+ *
+ *  Licensed 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.
+*/
+package openbook.server;
+
+import java.io.Serializable;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceContextType;
+
+/**
+ * An abstract utility for JPA based service. 
+ * This thin wrapper over a {@link EntityManagerFactory Persistence Unit} maintains
+ * <LI>per-thread persistence context
+ * <LI>relinquishes direct transaction control under a managed environment 
+ * 
+ * @see #getEntityManager()
+ * @see #newEntityManager()
+ * 
+ * @author Pinaki Poddar
+ * 
+ */
+@SuppressWarnings("serial")
+abstract class PersistenceService implements Serializable {
+    private final EntityManagerFactory emf;
+    private final String unitName;
+    private final boolean isManaged;
+    private final PersistenceContextType scope;
+    
+    private ThreadLocal<EntityManager> thread = new ThreadLocal<EntityManager>();
+    private ReentrantLock lock = new ReentrantLock();
+
+    protected PersistenceService(String unit, EntityManagerFactory emf, boolean managed, 
+            PersistenceContextType scope) {
+        this.unitName = unit;
+        this.emf = emf;
+        this.isManaged = managed;
+        this.scope = scope;
+    }
+    
+    public final EntityManagerFactory getUnit() {
+        return emf;
+    }
+
+    public final String getUnitName() {
+        return unitName;
+    }
+    
+    public final boolean isManaged() {
+        return isManaged;
+    }
+    
+    public final PersistenceContextType getContextType() {
+        return scope;
+    }
+
+    /**
+     * Gets an entity manager associated with the current thread. If the
+     * current thread is not associated with any entity manager or the
+     * associated entity manager has been closed, creates a new entity manager
+     * and associates with the current thread.
+     * 
+     * @return an entity manager associated with the current thread.
+     */
+    protected EntityManager getEntityManager() {
+        try {
+            lock.lock();
+            EntityManager em = thread.get();
+            if (em == null || !em.isOpen()) {
+                em = emf.createEntityManager();
+                thread.set(em);
+            }
+            return em;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Creates a new entity manager. The entity manager is not associated with
+     * the current thread.
+     */
+    protected EntityManager newEntityManager() {
+        return emf.createEntityManager();
+    }
+
+    /**
+     * Begins a transaction on the current thread. If the thread is associated
+     * with a persistence context, then a transaction is started if necessary.
+     * If the thread is not associated with a persistence context, then a new
+     * context is created, associated with the thread, new transaction is
+     * started.
+     * 
+     * @see #getEntityManager()
+     */
+    protected EntityManager begin() {
+        try {
+            lock.lock();
+            EntityManager em = getEntityManager();
+            if (isManaged) {
+                em.joinTransaction();
+            } else {
+                if (!em.getTransaction().isActive()) {
+                    em.getTransaction().begin();
+                }
+            }
+            return em;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Commits a transaction on the current thread.
+     */
+    protected void commit() {
+        try {
+            lock.lock();
+            EntityManager em = getEntityManager();
+            if (isManaged) {
+                em.flush();
+            } else {
+                assertActive();
+                em.getTransaction().commit();
+            }
+            if (scope == PersistenceContextType.TRANSACTION) {
+                em.clear();
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Rolls back a transaction on the current thread.
+     */
+    protected void rollback() {
+        try {
+            lock.lock();
+            EntityManager em = getEntityManager();
+            if (isManaged) {
+                
+            } else {
+                em.getTransaction().rollback();
+            }
+            if (scope == PersistenceContextType.TRANSACTION) {
+                em.clear();
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Assert current thread is associated with an active transaction.
+     */
+    protected void assertActive() {
+        EntityManager em = thread.get();
+        String thread = Thread.currentThread().getName();
+        assertTrue("No persistent context is associated with " + thread, em != null);
+        assertTrue("Persistent context " + em + " associated with " + thread + " has been closed", em.isOpen());
+        if (!isManaged) {
+            assertTrue("Persistent context " + em + " associated with " + thread + " has no active transaction", 
+                    em.getTransaction().isActive());
+        }
+    }
+
+    protected void assertTrue(String s, boolean p) {
+        if (!p) {
+            System.err.println(s);
+            throw new RuntimeException(s);
+        }
+    }
+}

Propchange: openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/PersistenceService.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/QueryDecorator.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/QueryDecorator.java?rev=944083&view=auto
==============================================================================
--- openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/QueryDecorator.java (added)
+++ openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/QueryDecorator.java Fri May 14 02:14:30 2010
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2010 Pinaki Poddar
+ *
+ *  Licensed 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.
+*/
+package openbook.server;
+
+import javax.persistence.Query;
+
+/**
+ * Decorates an executable query.
+ * Concrete decorative action can be binding parameters, limiting the result range etc.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public interface QueryDecorator {
+    void decorate(Query q);
+}

Propchange: openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/QueryDecorator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/QueryParameterBinder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/QueryParameterBinder.java?rev=944083&view=auto
==============================================================================
--- openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/QueryParameterBinder.java (added)
+++ openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/QueryParameterBinder.java Fri May 14 02:14:30 2010
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010-2012 Pinaki Poddar
+ *
+ *
+ *  Licensed 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.
+*/
+package openbook.server;
+
+import javax.persistence.Query;
+import javax.persistence.TypedQuery;
+
+/**
+ * Decorates a query by binding parameters.
+ *  
+ * @author Pinaki Poddar
+ *
+ */
+public class QueryParameterBinder implements QueryDecorator {
+    private final Object[] params;
+    
+    /**
+     * Construct a parameter binder with the given parameters.
+     * 
+     * @param params
+     */
+    public QueryParameterBinder(Object...params) {
+        this.params = params;
+    }
+    
+    @Override
+    public void decorate(Query query) {
+        if (params == null)
+            return;
+        for (int i = 0; i < params.length; i += 2) {
+            if (params[i] instanceof Integer) {
+                query.setParameter((Integer)params[i], params[i+1]);
+            } else if (params[i] instanceof String) {
+                query.setParameter((String)params[i], params[i+1]);
+            } else {
+                throw new IllegalArgumentException("Parameter index " + params[i] + 
+                        " is neither and integer nor String");
+            }
+        }
+    }
+}

Propchange: openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/QueryParameterBinder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/ServiceFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/ServiceFactory.java?rev=944083&view=auto
==============================================================================
--- openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/ServiceFactory.java (added)
+++ openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/ServiceFactory.java Fri May 14 02:14:30 2010
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010 Pinaki Poddar
+ *
+ *  Licensed 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.
+*/
+package openbook.server;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+import javax.persistence.PersistenceContextType;
+
+/**
+ * A container of persistence units. Typically a JEE container will create, manage and inject
+ * the persistence units to the user artifacts.  
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public class ServiceFactory {
+    private static final Map<String, OpenBookService> _services = 
+        new HashMap<String, OpenBookService>();
+    
+    /**
+     * Creates a persistence unit of given name configured with the given
+     * name-value parameters. 
+     * 
+     * @param unit name of the persistence unit. A <code>META-INF/persistence.xml</code> must be 
+     * available with the same unit name in the classpath.
+     */
+    public synchronized static OpenBookService getService(String unit) {
+        OpenBookService service = _services.get(unit);
+        if (service == null) {
+            EntityManagerFactory emf = Persistence.createEntityManagerFactory(unit);
+            service = new OpenBookServiceImpl(unit, emf, false, PersistenceContextType.TRANSACTION);
+            _services.put(unit, service);
+        }
+        return service;
+    }
+}

Propchange: openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/server/ServiceFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/util/PropertyHelper.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/util/PropertyHelper.java?rev=944083&view=auto
==============================================================================
--- openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/util/PropertyHelper.java (added)
+++ openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/util/PropertyHelper.java Fri May 14 02:14:30 2010
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2010-2012 Pinaki Poddar
+ *
+ *
+ *  Licensed 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.
+*/
+package openbook.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * A set of static utility functions to read properties from file, manage properties with multi-part keys,
+ * array style properties etc.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public class PropertyHelper {
+    /**
+     * Filter the properties by the given name.
+     * 
+     * @param name a part of the key
+     * @param prefix if true, property key must begin with the given name. Otherwise, the key merely contains the
+     * name to qualify. 
+     * @param
+     * 
+     * @return key-value pairs that match.
+     */
+    public static Map<String,Object> filter(Map<String,Object> props, String name, boolean prefix, 
+            boolean includeArrays) {
+        Map<String, Object> result = new HashMap<String, Object>();
+        for (String key : props.keySet()) {
+            if (key == null)
+                continue;
+            boolean match = prefix ? key.startsWith(name) : (key.indexOf(name) != -1);
+            if (match && !isArray(key)) {
+                result.put(key, props.get(key));
+            }
+        }
+        if (includeArrays) {
+            Map<String,List<Object>> arrayProperties = filterArrayKeys(props, name, prefix);
+            result.putAll(arrayProperties);
+        }
+        return result;
+    }
+    
+    /**
+     * Select only those property keys which ends with an array marker such as <code>openjpa.DataCache[1]</code>.
+     * The multiple values of the property is inserted into the resultant map as a List of object against the 
+     * original key. 
+     * <br>
+     * For example, if the original map had three key-value pairs as
+     * <LI><code>openjpa.DataCache[1]=true</code>  
+     * <LI><code>openjpa.DataCache[2]=false</code>
+     * <LI><code>openjpa.DataCache[3]=default</code>
+     * <br>
+     * Then that will result into a single entry in the resultant Map under the key <code>openjpa.DataCache</code>
+     * with a value as a List of three elements namely <code>{true, false, default}</code>. The array index values
+     * are not significant other than they must all be different for the same base key.
+     * 
+     * @param name part of the property key
+     * @param prefix does the name must appear as a prefix?
+     * 
+     * @return key-value pairs that match.
+     */
+    public static Map<String,List<Object>> filterArrayKeys(Map<String,Object> props, String name, boolean prefix) {
+        Map<String, List<Object>> result = new HashMap<String, List<Object>>();
+        for (String key : props.keySet()) {
+            boolean match = prefix ? key.startsWith(name) : (key.indexOf(name) != -1);
+            if (match && isArray(key)) {
+                String realKey = removeArray(key);
+                List<Object> values = result.get(realKey);
+                if (values == null) {
+                    values = new ArrayList<Object>();
+                    result.put(realKey, values);
+                }
+                values.add(props.get(key));
+            }
+        }
+        return result;
+    }
+
+    
+    /**
+     * Load properties from the given name resource.
+     * The given named resource is first looked up as resource on the current thread's context
+     * and if not found as a file input.
+     * 
+     * @param resource name a of resource. 
+     * 
+     * @return empty properties if no resource found.
+     */
+    public static Map<String,Object> load(String resource) {
+        Properties p = new Properties();
+        try {
+            InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource);
+            if (stream == null) {
+                stream = new FileInputStream(resource);
+            } 
+            p.load(stream);
+        } catch (Exception e) {
+            System.err.println("Error reading " + resource + " due to " + e);
+        }
+        return toMap(p);
+    }
+    
+    /**
+     * Affirm if the given resource is available either as a resource in the current thread's context classpath
+     * or as a file.
+     * 
+     */
+    public static boolean canFind(String resource) {
+        if (resource == null)
+            return false;
+        InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource);
+        if (stream != null)
+            return true;
+        return new File(resource).exists();
+    }
+    
+    public static Map<String, Object> toMap(Properties p) {
+        Map<String, Object> result = new HashMap<String, Object>();
+        for (Object k : p.keySet()) {
+            result.put(k.toString(), p.get(k));
+        }
+        return result;
+    }
+    
+    /**
+     * Overwrites any key-value pair in the given map for which a System property is available 
+     * @param original properties to be overwritten
+     * @return the original property overwritten with System properties
+     */
+    public static Map<String, Object> overwriteWithSystemProperties(Map<String, Object> original) {
+        Properties properties = System.getProperties();
+        for (Object syskey : properties.keySet()) {
+            if (original.containsKey(syskey)) {
+                original.put(syskey.toString(), properties.get(syskey));
+            }
+        }
+        return original;
+    }
+
+    
+    public static int getInteger(Map<String,Object> props, String key, int def) {
+        int result = def;
+        try {
+            Object value = props.get(key);
+            if (value != null)
+                result = Integer.parseInt(value.toString());
+        } catch (NumberFormatException nfe) {
+            
+        }
+        return result;
+    }
+    
+    public static double getDouble(Map<String,Object> props, String key, double def) {
+        double result = def;
+        try {
+            Object value = props.get(key);
+            if (value != null)
+                result = Double.parseDouble(value.toString());
+        } catch (NumberFormatException nfe) {
+            
+        }
+        return result;
+    }
+    
+    public static String getString(Map<String,Object> props, String key, String def) {
+        Object value = props.get(key);
+        if (value != null)
+            return value.toString();
+        return def;
+    }
+    
+    public static List<String> getStringList(Map<String,Object> props, String key) {
+        return getStringList(props, key, Collections.EMPTY_LIST);
+    }
+    
+    public static List<String> getStringList(Map<String,Object> props, String key, List<String> def) {
+        Object value = props.get(key);
+        if (value != null)
+            return Arrays.asList(value.toString().split("\\,"));
+        return def;
+    }
+    
+    /**
+     * Affirms if the given string using array [] symbol at the end.
+     * 
+     * @param key a string to check for array symbol.
+     */
+    private static boolean isArray(String key) {
+        if (key == null || key.length() < 3 || !key.endsWith("]"))
+            return false;
+        int i = key.indexOf("[");
+        if (i == -1 || i != key.lastIndexOf("["))
+            return false;
+        String index = key.substring(i+1,key.length()-1);
+        try {
+            Integer.parseInt(index);
+        } catch (NumberFormatException e) {
+            System.err.println("Bad index " + index + " in " + key);
+            return false;
+        }
+        return true;
+    }
+    
+    private static String removeArray(String key) {
+        int i = key.indexOf("[");
+        return key.substring(0,i);
+    }
+
+    public static Set<String> getSubsectionKeys(Set<String> keys, String section) {
+        String prefix = asPrefix(section);
+        Set<String> subsections = new HashSet<String>();
+        for (String key : keys) {
+            if (key.startsWith(prefix)) {
+                subsections.add(prefix + getPrefix(key.substring(prefix.length())));
+            }
+        }
+        return subsections;
+    }
+    
+    private static final String DOT = ".";
+    private static String asPrefix(String s) {
+        if (s.endsWith(DOT)) return s;
+        return s + DOT;
+    }
+    public static String getPrefix(String s) {
+        int i = s.indexOf(DOT);
+        return (i == -1) ? s : s.substring(0, i);
+    }
+    
+    /**
+     * Get the portion of the given map whose key has the given section at prefix.
+     * 
+     * @param props a set of name-value pair
+     * @param section a string representing section of a key
+     * 
+     * @return a new map with only the keys that starts with the given section. 
+     */
+    public static Map<String,Object> getSection(Map<String,Object> props, String section) {
+        return getSection(props, section, false);
+    }
+    
+    /**
+     * Get the portion of the given map whose key has the given section at prefix.
+     * 
+     * @param props a set of name-value pair
+     * @param section a string representing section of a key
+     * @param retain if true the key of resultant map is same as the original map. Otherwise
+     * the resultant map keys are without the section prefix.
+     * 
+     * @return the map with only the keys that starts with the given section. 
+     */
+    public static Map<String,Object> getSection(Map<String,Object> props, String section, boolean retain) {
+        Map<String,Object> result = new HashMap<String, Object>(props);
+        Set<String> keys = props.keySet();
+        String prefix = asPrefix(section);
+        for (String key : keys) {
+            if (key.startsWith(prefix)) {
+                String newKey = retain ? key : key.substring(prefix.length());
+                result.put(newKey, props.get(key));
+            }
+        }
+        return result;
+    }
+}

Propchange: openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/util/PropertyHelper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/util/Randomizer.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/util/Randomizer.java?rev=944083&view=auto
==============================================================================
--- openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/util/Randomizer.java (added)
+++ openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/util/Randomizer.java Fri May 14 02:14:30 2010
@@ -0,0 +1,95 @@
+package openbook.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+
+
+/**
+ * A set of static utility functions for simulating pseudo-randomness.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public class Randomizer {
+    private static final Random rng = new Random(System.currentTimeMillis());
+    private static final int MIN_ALPHA = (int)'A';
+    private static final int MAX_ALPHA = (int)'Z';
+
+    /**
+     * Returns true with a probability of p.
+     */
+    public static boolean probability(double p) {
+        return rng.nextDouble() < p;
+    }
+    
+    /**
+     * Picks a random number between 0 (inclusive) and N (exclusive).
+     */
+    public static int random(int n) {
+        return rng.nextInt(n);
+    }
+    
+    /**
+     * Picks a uniformly distributed random integer within the given range. 
+     */
+    public static int random(int min, int max) {
+        return min + rng.nextInt(max-min);
+    }
+    public static double random(double min, double max) {
+        return min + rng.nextDouble()*(max-min);
+    }
+    
+    /**
+     * Generates a random alphanumeric String with each segment separated by a dash. 
+     */
+    public static String randomString(int...segments) {
+        StringBuffer tmp = new StringBuffer();
+        for (int s : segments) {
+            tmp.append(tmp.length() == 0 ? (char)random(MIN_ALPHA, MAX_ALPHA) : '-');
+            for (int j = 0; j < s; j++)
+                tmp.append(random(10));
+        }
+        return tmp.toString();
+    }
+    
+    /**
+     * Picks a random element from the given list.
+     */
+    public static <T> T selectRandom(List<T> list) {
+        if (list == null || list.isEmpty())
+            return null;
+        if (list.size() == 1)
+            return list.get(0);
+        return list.get(random(list.size()));
+    }
+    
+    /**
+     * Selects n elements randomly from the given list.
+     * @param <T>
+     * @param list
+     * @param n
+     * @return
+     */
+    public static <T> List<T> selectRandom(List<T> list, int n) {
+        if (list == null || list.isEmpty())
+            return Collections.emptyList();
+        Set<Integer> indices = new HashSet<Integer>();
+        List<T> selected = new ArrayList<T>();
+        int m = list.size();
+        if (n >= m) {
+            selected.addAll(list);
+        } else {
+            while (indices.size() < n) {
+                indices.add(random(m));
+            }
+            for (Integer index : indices) {
+                selected.add(list.get(index));
+            }
+        }
+        return selected;
+    }
+}

Propchange: openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/util/Randomizer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/util/package.html
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/util/package.html?rev=944083&view=auto
==============================================================================
--- openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/util/package.html (added)
+++ openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/util/package.html Fri May 14 02:14:30 2010
@@ -0,0 +1,5 @@
+<html>
+<body>
+Common utility classes used by both OpenBook service and client.
+</body>
+</html>
\ No newline at end of file

Propchange: openjpa/trunk/openjpa-examples/openbooks/src/main/java/openbook/util/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-examples/openbooks/src/main/resources/source/jpa/tools/swing/AttributeLegendView.html
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-examples/openbooks/src/main/resources/source/jpa/tools/swing/AttributeLegendView.html?rev=944083&view=auto
==============================================================================
--- openjpa/trunk/openjpa-examples/openbooks/src/main/resources/source/jpa/tools/swing/AttributeLegendView.html (added)
+++ openjpa/trunk/openjpa-examples/openbooks/src/main/resources/source/jpa/tools/swing/AttributeLegendView.html Fri May 14 02:14:30 2010
@@ -0,0 +1,92 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html><head>
+<title></title>
+  <style type="text/css">
+    <!--code { font-family: Courier New, Courier; font-size: 14pt; margin: 0px; }-->
+  </style>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+</head><body>
+
+
+<!-- ======================================================== -->
+<!-- = Java Sourcecode to HTML automatically converted code = -->
+<!-- =   Java2Html Converter 5.0 [2006-02-26] by Markus Gebhard  markus@jave.de   = -->
+<!-- =     Further information: http://www.java2html.de     = -->
+<div align="left" class="java">
+<table border="0" cellpadding="3" cellspacing="0" bgcolor="#ffffff">
+   <tr>
+  <!-- start source code -->
+   <td nowrap="nowrap" valign="top" align="left">
+    <code>
+<font color="#808080">01</font>&nbsp;<font color="#3f7f5f">/*</font><br />
+<font color="#808080">02</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f7f5f">*&nbsp;Copyright&nbsp;2010-2012&nbsp;Pinaki&nbsp;Poddar</font><br />
+<font color="#808080">03</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f7f5f">*</font><br />
+<font color="#808080">04</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f7f5f">*</font><br />
+<font color="#808080">05</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f7f5f">*&nbsp;&nbsp;Licensed&nbsp;under&nbsp;the&nbsp;Apache&nbsp;License,&nbsp;Version&nbsp;2.0&nbsp;(the&nbsp;&#34;License&#34;);</font><br />
+<font color="#808080">06</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f7f5f">*&nbsp;&nbsp;you&nbsp;may&nbsp;not&nbsp;use&nbsp;this&nbsp;file&nbsp;except&nbsp;in&nbsp;compliance&nbsp;with&nbsp;the&nbsp;License.</font><br />
+<font color="#808080">07</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f7f5f">*&nbsp;&nbsp;You&nbsp;may&nbsp;obtain&nbsp;a&nbsp;copy&nbsp;of&nbsp;the&nbsp;License&nbsp;at</font><br />
+<font color="#808080">08</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f7f5f">*</font><br />
+<font color="#808080">09</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f7f5f">*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http://www.apache.org/licenses/LICENSE-2.0</font><br />
+<font color="#808080">10</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f7f5f">*</font><br />
+<font color="#808080">11</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f7f5f">*&nbsp;&nbsp;Unless&nbsp;required&nbsp;by&nbsp;applicable&nbsp;law&nbsp;or&nbsp;agreed&nbsp;to&nbsp;in&nbsp;writing,&nbsp;software</font><br />
+<font color="#808080">12</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f7f5f">*&nbsp;&nbsp;distributed&nbsp;under&nbsp;the&nbsp;License&nbsp;is&nbsp;distributed&nbsp;on&nbsp;an&nbsp;&#34;AS&nbsp;IS&#34;&nbsp;BASIS,</font><br />
+<font color="#808080">13</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f7f5f">*&nbsp;&nbsp;WITHOUT&nbsp;WARRANTIES&nbsp;OR&nbsp;CONDITIONS&nbsp;OF&nbsp;ANY&nbsp;KIND,&nbsp;either&nbsp;express&nbsp;or&nbsp;implied.</font><br />
+<font color="#808080">14</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f7f5f">*&nbsp;&nbsp;See&nbsp;the&nbsp;License&nbsp;for&nbsp;the&nbsp;specific&nbsp;language&nbsp;governing&nbsp;permissions&nbsp;and</font><br />
+<font color="#808080">15</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f7f5f">*&nbsp;&nbsp;limitations&nbsp;under&nbsp;the&nbsp;License.</font><br />
+<font color="#808080">16</font>&nbsp;<font color="#3f7f5f">*/</font><br />
+<font color="#808080">17</font>&nbsp;<font color="#7f0055"><b>package&nbsp;</b></font><font color="#000000">jpa.tools.swing;</font><br />
+<font color="#808080">18</font>&nbsp;<font color="#ffffff"></font><br />
+<font color="#808080">19</font>&nbsp;<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">java.awt.Color;</font><br />
+<font color="#808080">20</font>&nbsp;<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">java.awt.GridLayout;</font><br />
+<font color="#808080">21</font>&nbsp;<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">java.awt.image.BufferedImage;</font><br />
+<font color="#808080">22</font>&nbsp;<font color="#ffffff"></font><br />
+<font color="#808080">23</font>&nbsp;<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">javax.persistence.metamodel.Attribute;</font><br />
+<font color="#808080">24</font>&nbsp;<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">javax.swing.BorderFactory;</font><br />
+<font color="#808080">25</font>&nbsp;<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">javax.swing.ImageIcon;</font><br />
+<font color="#808080">26</font>&nbsp;<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">javax.swing.JComponent;</font><br />
+<font color="#808080">27</font>&nbsp;<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">javax.swing.JLabel;</font><br />
+<font color="#808080">28</font>&nbsp;<font color="#7f0055"><b>import&nbsp;</b></font><font color="#000000">javax.swing.JPanel;</font><br />
+<font color="#808080">29</font>&nbsp;<font color="#ffffff"></font><br />
+<font color="#808080">30</font>&nbsp;<font color="#3f5fbf">/**</font><br />
+<font color="#808080">31</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f5fbf">*&nbsp;Displays&nbsp;color&nbsp;codes&nbsp;of&nbsp;each&nbsp;attribute&nbsp;type.</font><br />
+<font color="#808080">32</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f5fbf">*&nbsp;</font><br />
+<font color="#808080">33</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f5fbf">*&nbsp;</font><font color="#7f9fbf">@author&nbsp;</font><font color="#3f5fbf">Pinaki&nbsp;Poddar</font><br />
+<font color="#808080">34</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f5fbf">*</font><br />
+<font color="#808080">35</font>&nbsp;<font color="#ffffff">&nbsp;</font><font color="#3f5fbf">*/</font><br />
+<font color="#808080">36</font>&nbsp;<font color="#646464">@SuppressWarnings</font><font color="#000000">(</font><font color="#2a00ff">&#34;serial&#34;</font><font color="#000000">)</font><br />
+<font color="#808080">37</font>&nbsp;<font color="#7f0055"><b>public&nbsp;class&nbsp;</b></font><font color="#000000">AttributeLegendView&nbsp;</font><font color="#7f0055"><b>extends&nbsp;</b></font><font color="#000000">JPanel&nbsp;</font><font color="#000000">{</font><br />
+<font color="#808080">38</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><br />
+<font color="#808080">39</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>public&nbsp;</b></font><font color="#000000">AttributeLegendView</font><font color="#000000">()&nbsp;{</font><br />
+<font color="#808080">40</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>super</b></font><font color="#000000">(</font><font color="#7f0055"><b>true</b></font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#808080">41</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">setBorder</font><font color="#000000">(</font><font color="#000000">BorderFactory.createTitledBorder</font><font color="#000000">(</font><font color="#2a00ff">&#34;Attribute&nbsp;Legends&#34;</font><font color="#000000">))</font><font color="#000000">;</font><br />
+<font color="#808080">42</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">setLayout</font><font color="#000000">(</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">GridLayout</font><font color="#000000">(</font><font color="#990000">0</font><font color="#000000">,</font><font color="#990000">3</font><font color="#000000">))</font><font color="#000000">;</font><br />
+<font color="#808080">43</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">add</font><font color="#000000">(</font><font color="#000000">createColoredLabel</font><font color="#000000">(</font><font color="#2a00ff">&#34;IDENTITY&#34;</font><font color="#000000">,&nbsp;Color.RED</font><font color="#000000">))</font><font color="#000000">;</font><br />
+<font color="#808080">44</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">add</font><font color="#000000">(</font><font color="#000000">createColoredLabel</font><font color="#000000">(</font><font color="#2a00ff">&#34;VERSION&#34;</font><font color="#000000">,&nbsp;Color.DARK_GRAY</font><font color="#000000">))</font><font color="#000000">;</font><br />
+<font color="#808080">45</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>for&nbsp;</b></font><font color="#000000">(</font><font color="#000000">Attribute.PersistentAttributeType&nbsp;type&nbsp;:&nbsp;Attribute.PersistentAttributeType.values</font><font color="#000000">())&nbsp;{</font><br />
+<font color="#808080">46</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">add</font><font color="#000000">(</font><font color="#000000">createColoredLabel</font><font color="#000000">(</font><font color="#000000">type.toString</font><font color="#000000">()</font><font color="#000000">.replace</font><font color="#000000">(</font><font color="#990000">'_'</font><font color="#000000">,&nbsp;</font><font color="#990000">'&nbsp;'</font><font color="#000000">)</font><font color="#000000">,&nbsp;MetamodelHelper.getColor</font><font color="#000000">(</font><font color="#000000">type</font><font color="#000000">)))</font><font color="#000000">;</font><br />
+<font color="#808080">47</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><br />
+<font color="#808080">48</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">}</font><br />
+<font color="#808080">49</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><br />
+<font color="#808080">50</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">JComponent&nbsp;createColoredLabel</font><font color="#000000">(</font><font color="#000000">String&nbsp;text,&nbsp;Color&nbsp;c</font><font color="#000000">)&nbsp;{</font><br />
+<font color="#808080">51</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>int&nbsp;</b></font><font color="#000000">width&nbsp;&nbsp;=&nbsp;</font><font color="#990000">40</font><font color="#000000">;</font><br />
+<font color="#808080">52</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>int&nbsp;</b></font><font color="#000000">height&nbsp;=&nbsp;</font><font color="#990000">20</font><font color="#000000">;</font><br />
+<font color="#808080">53</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">BufferedImage&nbsp;bimage&nbsp;=&nbsp;</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">BufferedImage</font><font color="#000000">(</font><font color="#000000">width,&nbsp;height,&nbsp;BufferedImage.TYPE_INT_RGB</font><font color="#000000">)</font><font color="#000000">;&nbsp;</font><br />
+<font color="#808080">54</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>for&nbsp;</b></font><font color="#000000">(</font><font color="#7f0055"><b>int&nbsp;</b></font><font color="#000000">i&nbsp;=&nbsp;</font><font color="#990000">0</font><font color="#000000">;&nbsp;i&nbsp;&lt;&nbsp;width;&nbsp;i++</font><font color="#000000">)</font><br />
+<font color="#808080">55</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>for&nbsp;</b></font><font color="#000000">(</font><font color="#7f0055"><b>int&nbsp;</b></font><font color="#000000">j&nbsp;=&nbsp;</font><font color="#990000">0</font><font color="#000000">;&nbsp;j&nbsp;&lt;&nbsp;height;&nbsp;j++</font><font color="#000000">)</font><br />
+<font color="#808080">56</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">bimage.setRGB</font><font color="#000000">(</font><font color="#000000">i,&nbsp;j,&nbsp;c.getRGB</font><font color="#000000">())</font><font color="#000000">;</font><br />
+<font color="#808080">57</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">JLabel&nbsp;label&nbsp;=&nbsp;</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">JLabel</font><font color="#000000">(</font><font color="#000000">text,&nbsp;</font><font color="#7f0055"><b>new&nbsp;</b></font><font color="#000000">ImageIcon</font><font color="#000000">(</font><font color="#000000">bimage</font><font color="#000000">)</font><font color="#000000">,&nbsp;JLabel.LEADING</font><font color="#000000">)</font><font color="#000000">;</font><br />
+<font color="#808080">58</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#7f0055"><b>return&nbsp;</b></font><font color="#000000">label;</font><br />
+<font color="#808080">59</font>&nbsp;<font color="#ffffff">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#000000">}</font><br />
+<font color="#808080">60</font>&nbsp;<font color="#ffffff"></font><br />
+<font color="#808080">61</font>&nbsp;<font color="#000000">}</font></code>
+    
+   </td>
+  <!-- end source code -->
+   </tr>
+</table>
+</div>
+<!-- =       END of automatically generated HTML code       = -->
+<!-- ======================================================== -->
+
+
+</body></html>
\ No newline at end of file