Example usage for javax.ejb TransactionAttributeType REQUIRED

List of usage examples for javax.ejb TransactionAttributeType REQUIRED

Introduction

In this page you can find the example usage for javax.ejb TransactionAttributeType REQUIRED.

Prototype

TransactionAttributeType REQUIRED

To view the source code for javax.ejb TransactionAttributeType REQUIRED.

Click Source Link

Document

If a client invokes the enterprise bean's method while the client is associated with a transaction context, the container invokes the enterprise bean's method in the client's transaction context.

Usage

From source file:com.flexive.ejb.beans.ContentEngineBean.java

/**
 * {@inheritDoc}// w w  w.  j a v a  2s  .com
 */
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void convertContentType(FxPK contentPK, long destinationTypeId, boolean allowLossy, boolean allVersions)
        throws FxApplicationException {
    final FxContent content = load(contentPK);
    final FxType sourceType = CacheAdmin.getEnvironment().getType(content.getTypeId());
    FxPermissionUtils.checkTypeAvailable(destinationTypeId, false);
    final FxType destinationType = CacheAdmin.getEnvironment().getType(destinationTypeId);
    final UserTicket ticket = FxContext.getUserTicket();
    Connection con = null;
    final long sourceTypeId = sourceType.getId();
    try {
        if (sourceTypeId == destinationTypeId)
            throw new FxContentTypeConversionException("ex.content.typeconversion.desteqSourceError");

        // only a supervisor or a user whose ACL both belongs to the current content, to the current type and the destination type may
        // move the content
        boolean userPermitted = false;
        if (ticket.isGlobalSupervisor() || ticket.isMandatorSupervisor())
            userPermitted = true;
        if (!userPermitted) {
            if (!FxPermissionUtils.currentUserInACLList(ticket, Arrays.asList(sourceType.getACL().getId())))
                throw new FxContentTypeConversionException("ex.content.typeconversion.sourceTypeACLError");
            if (!FxPermissionUtils.currentUserInACLList(ticket,
                    Arrays.asList(destinationType.getACL().getId())))
                throw new FxContentTypeConversionException("ex.content.typeconversion.destinationTypeACLError");
            if (!FxPermissionUtils.currentUserInACLList(ticket, content.getAclIds()))
                throw new FxContentTypeConversionException("ex.content.typeconversion.notInContentACL");
        }

        // either destination ist derived from source or vice versa, or both types have to have the same supertype
        if (sourceType.getParent() == null && destinationType.getParent() == null)
            throw new FxContentTypeConversionException("ex.content.typeconversion.derivedTypeError");
        if (!sourceType.isDerivedFrom(destinationTypeId) && !destinationType.isDerivedFrom(sourceTypeId)) {
            // check for an indirect parentage (same supertype)
            FxType o1 = null;
            FxType o2 = null;
            for (FxType t = sourceType; t != null; t = t.getParent())
                o1 = t;
            for (FxType t = destinationType; t != null; t = t.getParent())
                o2 = t;

            if (o1.getId() != o2.getId())
                throw new FxContentTypeConversionException("ex.content.typeconversion.derivedTypeError");
        }

        /**
         * Inner class to convert a List of FxAssignments to a Map of ids / XPaths w/o leading types
         * The method omits systeminternal fields
         */
        final class XPathConverter {
            Map<Long, String> convertNoTypesAsMap(List<FxAssignment> ass, boolean propAssignsOnly) {
                final Map<Long, String> out = new HashMap<Long, String>(ass.size());
                for (FxAssignment a : ass) {
                    if (!a.isSystemInternal()) {
                        if (propAssignsOnly && a instanceof FxPropertyAssignment)
                            out.put(a.getId(), XPathElement.stripType(a.getXPath()));
                        else if (!propAssignsOnly)
                            out.put(a.getId(), XPathElement.stripType(a.getXPath()));
                    }
                }
                return out;
            }
        }

        final List<FxAssignment> sourceTypeAssignments = sourceType.getAllAssignments();
        final List<FxAssignment> destinationTypeAssignments = destinationType.getAllAssignments();
        final XPathConverter xPathConverter = new XPathConverter();
        // determine outcome for lossy / lossless conversion - evaluation is based on XPaths (their names, resp)
        final Map<Long, String> sourcePathsMap = xPathConverter.convertNoTypesAsMap(sourceTypeAssignments,
                true);
        final Map<Long, String> destPathsMap = xPathConverter.convertNoTypesAsMap(destinationTypeAssignments,
                true);
        final List<String> sourcePaths = new ArrayList<String>(sourcePathsMap.values());
        Collections.sort(sourcePaths);
        final List<String> destPaths = new ArrayList<String>(destPathsMap.values());
        Collections.sort(destPaths);

        final FxDiff diff = new FxDiff(sourcePaths, destPaths);
        final List<FxDiff.Difference> diffList = diff.diff();
        // a map which holds assignment ids / xpaths which will be removed from the source content (lossy conversion)
        final Map<Long, String> sourceRemoveMap = new HashMap<Long, String>(2);
        if (diffList.size() > 0) { // check if the differences have an impact on !lossy conversion
            for (FxDiff.Difference d : diffList) {
                if (d.getDeletedStart() == d.getDeletedEnd() && d.getAddedStart() == d.getAddedEnd()) {
                    throw new FxContentTypeConversionException("ex.content.typeconversion.xpathsDiffError");
                } else if (d.getDeletedStart() == d.getDeletedEnd() && d.getAddedStart() != d.getAddedEnd()) {
                    // lossy conversion check
                    if (!allowLossy) {
                        throw new FxContentTypeConversionException("ex.content.typeconversion.sourceLossError");
                    } else { // add to list of xPaths / assignments t.b. removed
                        // sourcePathsMap.
                        final String removePath = sourcePaths.get(d.getDeletedStart());
                        for (Map.Entry<Long, String> pathEntry : sourcePathsMap.entrySet()) {
                            if (pathEntry.getValue().equals(removePath))
                                sourceRemoveMap.put(pathEntry.getKey(), removePath);
                        }
                    }
                } // else: del start != del end (del end is neg.) and add start & end the same, then dest has an add. prop
            }
        }

        // a map for all sourceTypePropAssignmentIds vs. destinationTypePropAssignmentIds,
        // where null values mean that the destination assignments do not exist (data will be lost)
        final Map<Long, Long> assignmentMap = new HashMap<Long, Long>(5);
        // a List containing all destination assignments which are in the flatstore
        final List<Long> flatStoreAssignments = new ArrayList<Long>(5);
        final List<Long> nonFlatSourceAssignments = new ArrayList<Long>(5);
        final List<Long> nonFlatDestinationAssignments = new ArrayList<Long>(5);

        for (FxAssignment a : sourceTypeAssignments) {
            if (a.isSystemInternal() || !(a instanceof FxPropertyAssignment))
                continue;
            FxPropertyAssignment pa = (FxPropertyAssignment) a;
            final String sourceXPath = XPathElement.stripType(pa.getXPath());
            // get the corresponding assignment from the destination type
            final String destinationXPath = destinationType.getName() + sourceXPath;
            if (destPaths.contains(sourceXPath)
                    && CacheAdmin.getEnvironment().assignmentExists(destinationXPath)) {
                // if the dest assignment exists, test that the datatype is the same as for the source
                final FxAssignment destAssignment = CacheAdmin.getEnvironment().getAssignment(destinationXPath);
                if (!(destAssignment instanceof FxPropertyAssignment))
                    throw new FxContentTypeConversionException("ex.content.typeconversion.destneqprop",
                            destAssignment.getId());

                final FxDataType sourceDT = pa.getProperty().getDataType();
                final FxDataType destDT = ((FxPropertyAssignment) destAssignment).getProperty().getDataType();
                if (sourceDT != destDT)
                    throw new FxContentTypeConversionException("ex.content.typeconversion.destDTneqsourceDT",
                            destinationXPath);
                if (((FxPropertyAssignment) destAssignment).isFlatStorageEntry()) {
                    flatStoreAssignments.add(destAssignment.getId());
                } else {
                    nonFlatDestinationAssignments.add(destAssignment.getId());
                }
                if (!pa.isFlatStorageEntry()) {
                    nonFlatSourceAssignments.add(pa.getId());
                }
                assignmentMap.put(pa.getId(), destAssignment.getId());
            } else {
                assignmentMap.put(pa.getId(), null);
            }
        }

        // check if we have any mandatory assignments in our destination type and if we've got data for it
        for (FxAssignment a : destinationTypeAssignments) {
            if (a instanceof FxPropertyAssignment && !a.isSystemInternal()) {
                final int minMult = a.getMultiplicity().getMin();
                if (minMult > 0) {
                    final String destXPath = XPathElement.stripType(a.getXPath());
                    if (content.getData(destXPath).size() < minMult)
                        throw new FxContentTypeConversionException(
                                "ex.content.typeconversion.destMultiplicityError", destXPath, a.getId(),
                                minMult);
                }
            }
        }

        // passed all tests, start moving the content after retrieving all versions
        con = Database.getDbConnection();
        ContentStorage storage = StorageManager.getContentStorage(contentPK.getStorageMode());
        FxEnvironment env = CacheAdmin.getEnvironment();
        storage.convertContentType(con, contentPK, sourceTypeId, destinationTypeId, allVersions, assignmentMap,
                flatStoreAssignments, nonFlatSourceAssignments, nonFlatDestinationAssignments, sourcePathsMap,
                destPathsMap, sourceRemoveMap, env);

    } catch (FxApplicationException e) {
        EJBUtils.rollback(ctx);
        throw new FxContentTypeConversionException("ex.content.typeconversion.error", e.getMessage(), contentPK,
                sourceTypeId, destinationType.getId());
    } catch (SQLException e) {
        EJBUtils.rollback(ctx);
        LOG.error(e);
    } finally { // flush cache after update was completed
        Database.closeObjects(ContentEngineBean.class, con, null);
        CacheAdmin.expireCachedContent(contentPK.getId());
    }
}

From source file:org.nightlabs.jfire.accounting.AccountingManagerBean.java

@TransactionAttribute(TransactionAttributeType.REQUIRED)
@RolesAllowed("org.nightlabs.jfire.accounting.editInvoice")
@Override//from w  ww  .java  2  s. c  o m
public Invoice createInvoice(final Collection<ArticleID> articleIDs, final String invoiceIDPrefix,
        final boolean get, final String[] fetchGroups, final int maxFetchDepth) throws InvoiceEditException {
    final PersistenceManager pm = createPersistenceManager();
    try {
        pm.getExtent(Article.class);
        final User user = User.getUser(pm, getPrincipal());
        final Trader trader = Trader.getTrader(pm);
        final Accounting accounting = trader.getAccounting();

        final ArrayList<Article> articles = new ArrayList<Article>(articleIDs.size());
        for (final ArticleID articleID : articleIDs) {
            final Article article = (Article) pm.getObjectById(articleID);
            final Offer offer = article.getOffer();
            trader.validateOffer(offer);
            trader.acceptOfferImplicitely(offer);
            articles.add(article);
        }

        final Invoice invoice = accounting.createInvoice(user, articles, invoiceIDPrefix);
        accounting.validateInvoice(invoice);

        if (get) {
            pm.getFetchPlan().setMaxFetchDepth(maxFetchDepth);
            pm.getFetchPlan()
                    .setDetachmentOptions(FetchPlan.DETACH_LOAD_FIELDS + FetchPlan.DETACH_UNLOAD_FIELDS);
            if (fetchGroups != null)
                pm.getFetchPlan().setGroups(fetchGroups);

            return pm.detachCopy(invoice);
        }
        return null;
    } finally {
        pm.close();
    }
}

From source file:org.cesecore.certificates.certificate.CertificateStoreSessionBean.java

License:asdf

@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public boolean setStatus(AuthenticationToken admin, String fingerprint, int status)
        throws IllegalArgumentException, AuthorizationDeniedException {

    if ((status == CertificateConstants.CERT_REVOKED) || (status == CertificateConstants.CERT_ACTIVE)) {
        final String msg = INTRES.getLocalizedMessage("store.errorsetstatusargument", fingerprint, status);
        throw new IllegalArgumentException(msg);
    }/*from   w  ww.  j a  v a  2s .co  m*/
    CertificateData data = CertificateData.findByFingerprint(entityManager, fingerprint);
    if (data != null) {
        if (log.isDebugEnabled()) {
            log.debug("Set status " + status + " for certificate with fp: " + fingerprint);
        }

        // Must be authorized to CA in order to change status is certificates issued by the CA
        String bcdn = CertTools.stringToBCDNString(data.getIssuerDN());
        int caid = bcdn.hashCode();
        authorizedToCA(admin, caid);

        data.setStatus(status);
        final String serialNo = CertTools.getSerialNumberAsString(data.getCertificate(this.entityManager));
        final String msg = INTRES.getLocalizedMessage("store.setstatus", data.getUsername(), fingerprint,
                status, data.getSubjectDN(), data.getIssuerDN(), serialNo);
        Map<String, Object> details = new LinkedHashMap<String, Object>();
        details.put("msg", msg);
        logSession.log(EventTypes.CERT_CHANGEDSTATUS, EventStatus.SUCCESS, ModuleTypes.CERTIFICATE,
                ServiceTypes.CORE, admin.toString(), String.valueOf(caid), serialNo, data.getUsername(),
                details);
    } else {
        if (log.isDebugEnabled()) {
            final String msg = INTRES.getLocalizedMessage("store.setstatusfailed", fingerprint, status);
            log.debug(msg);
        }
    }
    return (data != null);
}

From source file:org.nightlabs.jfire.accounting.AccountingManagerBean.java

@TransactionAttribute(TransactionAttributeType.REQUIRED)
@RolesAllowed("org.nightlabs.jfire.accounting.editInvoice")
@Override//from  ww w.  j  a va 2 s . c om
public Invoice createInvoice(final ArticleContainerID articleContainerID, final String invoiceIDPrefix,
        final boolean get, final String[] fetchGroups, final int maxFetchDepth) throws InvoiceEditException {
    final PersistenceManager pm = createPersistenceManager();
    try {
        if (articleContainerID == null)
            throw new IllegalArgumentException("articleContainerID must not be null!");

        if (articleContainerID instanceof OrderID)
            pm.getExtent(Order.class);
        else if (articleContainerID instanceof OfferID)
            pm.getExtent(Offer.class);
        else if (articleContainerID instanceof DeliveryNoteID)
            pm.getExtent(DeliveryNote.class);
        else
            throw new IllegalArgumentException(
                    "articleContainerID must be an instance of OrderID, OfferID or DeliveryNoteID, but is "
                            + articleContainerID.getClass().getName());

        final ArticleContainer articleContainer = (ArticleContainer) pm.getObjectById(articleContainerID);

        final User user = User.getUser(pm, getPrincipal());
        final Trader trader = Trader.getTrader(pm);
        final Accounting accounting = trader.getAccounting();

        if (articleContainer instanceof Offer) {
            final Offer offer = (Offer) articleContainer;
            //            OfferLocal offerLocal = offer.getOfferLocal();
            trader.validateOffer(offer);
            trader.acceptOfferImplicitely(offer);
            //            trader.finalizeOffer(user, offer);
            //            trader.acceptOffer(user, offerLocal);
            //            trader.confirmOffer(user, offerLocal);
        } else {
            final Set<Offer> offers = new HashSet<Offer>();
            for (final Article article : articleContainer.getArticles()) {
                final Offer offer = article.getOffer();
                offers.add(offer);
            }
            for (final Iterator<Offer> it = offers.iterator(); it.hasNext();) {
                final Offer offer = it.next();
                if (!offer.isAborted()) {
                    trader.validateOffer(offer);
                    trader.acceptOfferImplicitely(offer);
                }
                //               trader.finalizeOffer(user, offer);
                //               trader.acceptOffer(user, offerLocal);
                //               trader.confirmOffer(user, offerLocal);
            }
        }

        final Invoice invoice = accounting.createInvoice(user, articleContainer, invoiceIDPrefix);
        accounting.validateInvoice(invoice);

        if (get) {
            pm.getFetchPlan().setMaxFetchDepth(maxFetchDepth);
            pm.getFetchPlan()
                    .setDetachmentOptions(FetchPlan.DETACH_LOAD_FIELDS + FetchPlan.DETACH_UNLOAD_FIELDS);
            if (fetchGroups != null)
                pm.getFetchPlan().setGroups(fetchGroups);

            return pm.detachCopy(invoice);
        }
        return null;
    } finally {
        pm.close();
    }
}

From source file:com.stratelia.webactiv.kmelia.control.ejb.KmeliaBmEJB.java

/**
 * Create a new Publication (only the header - parameters) to the current Topic
 *
 * @param pubDetail a PublicationDetail/*from   w w  w .j a  v a  2 s . c  om*/
 * @return the id of the new publication
 * @see com.stratelia.webactiv.util.publication.model.PublicationDetail
 * @since 1.0
 */
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public String createPublicationIntoTopic(PublicationDetail pubDetail, NodePK fatherPK) {
    PdcClassificationService classifier = PdcServiceFactory.getFactory().getPdcClassificationService();
    PdcClassification predefinedClassification = classifier.findAPreDefinedClassification(fatherPK.getId(),
            fatherPK.getInstanceId());
    return createPublicationIntoTopic(pubDetail, fatherPK, predefinedClassification);
}

From source file:com.stratelia.webactiv.kmelia.control.ejb.KmeliaBmEJB.java

@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public String createPublicationIntoTopic(PublicationDetail pubDetail, NodePK fatherPK,
        PdcClassification classification) {
    SilverTrace.info("kmelia", "KmeliaBmEJB.createPublicationIntoTopic()", "root.MSG_GEN_ENTER_METHOD");
    String pubId = null;/*from  w w  w .  j a va2  s  .  co  m*/
    try {
        pubId = createPublicationIntoTopicWithoutNotifications(pubDetail, fatherPK, classification);

        // creates todos for publishers
        createTodosForPublication(pubDetail, true);

        // alert supervisors
        sendAlertToSupervisors(fatherPK, pubDetail);

        // alert subscribers
        sendSubscriptionsNotification(pubDetail, false, false);

    } catch (Exception e) {
        throw new KmeliaRuntimeException("KmeliaBmEJB.createPublicationIntoTopic()", ERROR,
                "kmelia.EX_IMPOSSIBLE_DE_CREER_LA_PUBLICATION", e);
    }
    SilverTrace.info("kmelia", "KmeliaBmEJB.createPublicationIntoTopic()", "root.MSG_GEN_EXIT_METHOD");
    return pubId;
}

From source file:com.flexive.ejb.beans.structure.TypeEngineBean.java

/**
 * {@inheritDoc}//  w  w  w  .j a  v  a  2s. c  om
 */
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public String export(long id) throws FxApplicationException {
    return ConversionEngine.getXStream().toXML(CacheAdmin.getEnvironment().getType(id));
}

From source file:com.flexive.ejb.beans.structure.TypeEngineBean.java

/**
 * {@inheritDoc}//from   w ww .  j av a 2 s  . co  m
 */
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public FxType importType(String typeXML) throws FxApplicationException {
    try {
        return (FxType) ConversionEngine.getXStream().fromXML(typeXML);
    } catch (ConversionException e) {
        String key;
        Iterator i = e.keys();
        String path = "unknown";
        String line = "unknown";
        while (i.hasNext()) {
            key = (String) i.next();
            if ("path".equals(key))
                path = e.get(key);
            else if ("line number".equals(key))
                line = e.get(key);
        }
        throw new FxApplicationException(e.getCause(), "ex.structure.import.type.conversionError", path, line,
                e.getShortMessage());
    } catch (Exception e) {
        throw new FxApplicationException(e, "ex.structure.import.type.error", e.getMessage());
    }
}

From source file:org.nightlabs.jfire.accounting.AccountingManagerBean.java

@TransactionAttribute(TransactionAttributeType.REQUIRED)
@RolesAllowed("org.nightlabs.jfire.accounting.editInvoice")
@Override/*from  w w  w . j  av  a  2s  .c  o  m*/
public Invoice addArticlesToInvoice(final InvoiceID invoiceID, final Collection<ArticleID> articleIDs,
        final boolean validate, final boolean get, final String[] fetchGroups, final int maxFetchDepth)
        throws InvoiceEditException {
    final PersistenceManager pm = createPersistenceManager();
    try {
        pm.getExtent(Invoice.class);
        pm.getExtent(Article.class);
        final Trader trader = Trader.getTrader(pm);

        final Invoice invoice = (Invoice) pm.getObjectById(invoiceID);
        final Collection<Article> articles = new ArrayList<Article>(articleIDs.size());
        for (final ArticleID articleID : articleIDs) {
            final Article article = (Article) pm.getObjectById(articleID);
            final Offer offer = article.getOffer();
            trader.validateOffer(offer);
            trader.acceptOfferImplicitely(offer);
            articles.add(article);
        }

        final Accounting accounting = Accounting.getAccounting(pm);
        accounting.addArticlesToInvoice(User.getUser(pm, getPrincipal()), invoice, articles);

        if (validate)
            accounting.validateInvoice(invoice);

        if (!get)
            return null;

        pm.getFetchPlan().setMaxFetchDepth(maxFetchDepth);
        if (fetchGroups != null)
            pm.getFetchPlan().setGroups(fetchGroups);

        return pm.detachCopy(invoice);
    } finally {
        pm.close();
    }
}

From source file:com.flexive.ejb.beans.PhraseEngineBean.java

/**
 * {@inheritDoc}//from  w w w  .j  a  v a  2 s .  c om
 */
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void moveTreeNode(int category, long nodeId, long mandatorId, int delta)
        throws FxNoAccessException, FxNotFoundException {
    if (delta == 0)
        return;
    checkMandatorAccess(mandatorId, FxContext.getUserTicket());
    Connection con = null;
    PreparedStatement ps = null;
    try {
        // Obtain a database connection
        con = Database.getDbConnection();
        ps = con.prepareStatement("SELECT PARENTID, PARENTMANDATOR FROM " + TBL_PHRASE_TREE
                + " WHERE ID=? AND MANDATOR=? AND CAT=?");
        ps.setLong(1, nodeId);
        ps.setLong(2, mandatorId);
        ps.setInt(3, category);
        ResultSet rs = ps.executeQuery();
        if (rs == null || !rs.next())
            throw new FxNotFoundException("ex.phrases.node.notFound.id", nodeId, mandatorId);
        long parentId = rs.getLong(1);
        if (rs.wasNull())
            parentId = -1L;
        long parentMandatorId = rs.getLong(2);
        if (rs.wasNull())
            parentMandatorId = -1L;
        rs.close();
        ps.close();
        //0..node id, 1..pos
        List<Long> positions = Lists.newArrayListWithCapacity(10);

        if (parentId == -1L) {
            ps = con.prepareStatement("SELECT ID FROM " + TBL_PHRASE_TREE
                    + " WHERE PARENTID IS NULL AND MANDATOR=? AND CAT=? ORDER BY POS");
            ps.setLong(1, mandatorId);
            ps.setInt(2, category);
        } else {
            ps = con.prepareStatement("SELECT ID FROM " + TBL_PHRASE_TREE
                    + " WHERE PARENTID=? AND PARENTMANDATOR=? AND MANDATOR=? AND CAT=? ORDER BY POS");
            ps.setLong(1, parentId);
            ps.setLong(2, parentMandatorId);
            ps.setLong(3, mandatorId);
            ps.setInt(4, category);
        }
        rs = ps.executeQuery();
        long currPos = 1;
        int index = -1;
        while (rs != null && rs.next()) {
            if (index == -1 && nodeId == rs.getLong(1))
                index = (int) currPos - 1;
            positions.add(rs.getLong(1));
            currPos++;
        }
        if (positions.size() < 2) //only one node, can not change position
            return;
        int newIndex = index + delta;
        if (newIndex < 0)
            newIndex = 0;
        if (delta > 0)
            newIndex++;
        if (newIndex > (positions.size() - 1))
            newIndex = positions.size();
        positions.add(newIndex, nodeId);
        if (newIndex > index)
            positions.remove(index);
        else
            positions.remove(index + 1);
        //write back new positions
        ps.close();
        ps = con.prepareStatement(
                "UPDATE " + TBL_PHRASE_TREE + " SET POS=? WHERE ID=? AND MANDATOR=? AND CAT=?");
        ps.setLong(3, mandatorId);
        ps.setInt(4, category);
        for (int i = 1; i <= positions.size(); i++) {
            ps.setLong(1, i);
            ps.setLong(2, positions.get(i - 1));
            ps.addBatch();
        }
        ps.executeBatch();
    } catch (SQLException exc) {
        EJBUtils.rollback(ctx);
        throw new FxDbException(LOG, exc, "ex.db.sqlError", exc.getMessage()).asRuntimeException();
    } finally {
        Database.closeObjects(PhraseEngineBean.class, con, ps);
    }
}