001/*
002 * (C) Copyright 2009 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Anahide Tchertchian
018 */
019package org.nuxeo.ecm.platform.error.web;
020
021import static org.jboss.seam.ScopeType.EVENT;
022
023import java.io.Serializable;
024import java.util.Collections;
025import java.util.HashMap;
026import java.util.List;
027import java.util.Map;
028
029import javax.persistence.EntityManager;
030
031import org.apache.commons.logging.Log;
032import org.apache.commons.logging.LogFactory;
033import org.jboss.seam.ScopeType;
034import org.jboss.seam.annotations.Factory;
035import org.jboss.seam.annotations.In;
036import org.jboss.seam.annotations.Name;
037import org.jboss.seam.annotations.Scope;
038import org.nuxeo.common.utils.IdUtils;
039import org.nuxeo.ecm.core.api.CoreSession;
040import org.nuxeo.ecm.core.api.DocumentModel;
041import org.nuxeo.ecm.core.api.DocumentSecurityException;
042import org.nuxeo.ecm.core.api.NuxeoException;
043import org.nuxeo.ecm.core.api.PathRef;
044import org.nuxeo.ecm.core.api.RecoverableClientException;
045import org.nuxeo.ecm.core.persistence.PersistenceProviderFactory;
046import org.nuxeo.ecm.directory.DirectoryException;
047import org.nuxeo.ecm.directory.Session;
048import org.nuxeo.ecm.directory.api.DirectoryService;
049import org.nuxeo.ecm.platform.audit.api.AuditReader;
050import org.nuxeo.ecm.platform.audit.api.LogEntry;
051import org.nuxeo.ecm.platform.audit.api.Logs;
052import org.nuxeo.ecm.platform.audit.service.LogEntryProvider;
053import org.nuxeo.runtime.api.Framework;
054import org.nuxeo.runtime.transaction.TransactionHelper;
055
056/**
057 * Seam component performing errors
058 *
059 * @author Anahide Tchertchian
060 */
061@Name("errorSeamComponent")
062@Scope(ScopeType.CONVERSATION)
063public class SeamErrorComponent implements Serializable {
064
065    private static final long serialVersionUID = 1L;
066
067    private static final Log log = LogFactory.getLog(SeamErrorComponent.class);
068
069    @In(create = true, required = false)
070    protected transient CoreSession documentManager;
071
072    protected void createNewDocument() {
073        DocumentModel newDocument = documentManager.createDocumentModel("Workspace");
074        String title = "Test document";
075        newDocument.setProperty("dublincore", "title", "Test document");
076        String parentDocumentPath = "/default-domain/workspaces";
077        String name = IdUtils.generateId(title, "-", true, 24);
078        newDocument.setPathInfo(parentDocumentPath, name);
079
080        newDocument = documentManager.createDocument(newDocument);
081        documentManager.save();
082    }
083
084    public void checkedErrorAfterCreation() {
085        createNewDocument();
086        throw new NuxeoException("Checked exception after document creation");
087    }
088
089    public void uncheckedErrorAfterCreation() {
090        try {
091            createNewDocument();
092        } catch (NuxeoException e) {
093            log.error("********** Unexpected exception while testing error handling ***********");
094        }
095        throw new NullPointerException("Unchecked exception after document creation");
096    }
097
098    public String getCheckedError() {
099        throw new NuxeoException("Checked error on getter");
100    }
101
102    public String getUncheckedError() {
103        throw new NullPointerException("Unchecked error on getter");
104    }
105
106    public String getSecurityError() throws DocumentSecurityException {
107        throw new DocumentSecurityException("Security error on getter");
108    }
109
110    @Factory(value = "checkedErrorFactoryEvent", scope = EVENT)
111    public String getCheckedErrorFactoryEvent() {
112        throw new NuxeoException("Checked error on factory, scope event");
113    }
114
115    @Factory(value = "uncheckedErrorFactoryEvent", scope = EVENT)
116    public String getUncheckedErrorFactoryEvent() {
117        throw new NullPointerException("Unchecked error on factory, scope event");
118    }
119
120    @Factory(value = "securityErrorFactoryEvent", scope = EVENT)
121    public String getSecurityErrorFactoryEvent() throws DocumentSecurityException {
122        throw new DocumentSecurityException("Security error on factory, scope event");
123    }
124
125    public String performCheckedError() {
126        throw new NuxeoException("Checked error on action");
127    }
128
129    public String performUncheckedError() {
130        throw new NullPointerException("Unchecked error on action");
131    }
132
133    public String performSecurityError() throws DocumentSecurityException {
134        throw new DocumentSecurityException("Security error on action");
135    }
136
137    /**
138     * @since 5.8
139     */
140    public String performRecoverableClientException() throws RecoverableClientException {
141        throw new RecoverableClientException("Application validation failed, rollingback",
142                "Application validation failed, rollingback", null);
143    }
144
145    /**
146     * @since 5.8
147     */
148    public String performPureRollback() {
149        TransactionHelper.setTransactionRollbackOnly();
150        return null;
151    }
152
153    /**
154     * @since 5.9.5
155     */
156    public void performDistributedRollback() {
157        createDummyUser();
158        createDummyLogEntry();
159        createDummyDoc();
160        TransactionHelper.setTransactionRollbackOnly();
161    }
162
163    /**
164     * @since 5.9.5
165     */
166    public void clearDistributedRollbackEnv() {
167        clearDummyUser();
168        clearDummyDoc();
169        clearDummyLogEntries();
170    }
171
172    protected DocumentModel createDummyUser() {
173        DirectoryService directories = Framework.getService(DirectoryService.class);
174        try (Session userDir = directories.getDirectory("userDirectory").getSession()) {
175            Map<String, Object> user = new HashMap<>();
176            user.put("username", "dummy");
177            user.put("password", "dummy");
178            user.put("firstName", "dummy");
179            user.put("lastName", "dummy");
180            return userDir.createEntry(user);
181        }
182    }
183
184    protected void clearDummyUser() throws DirectoryException {
185        DirectoryService directories = Framework.getService(DirectoryService.class);
186        try (Session userDir = directories.open("userDirectory")) {
187            userDir.deleteEntry("dummy");
188        }
189    }
190
191    /**
192     * @since 5.9.5
193     */
194    @Factory(scope = ScopeType.EVENT)
195    public boolean isDummyUserExists() throws DirectoryException {
196        DirectoryService directories = Framework.getService(DirectoryService.class);
197        try (Session userDir = directories.getDirectory("userDirectory").getSession()) {
198            DocumentModel user = userDir.getEntry("dummy");
199            return user != null;
200        } catch (DirectoryException cause) {
201            return false;
202        }
203    }
204
205    protected LogEntry createDummyLogEntry() {
206        Logs logs = Framework.getService(Logs.class);
207        LogEntry entry = logs.newLogEntry();
208        entry.setEventId("dummy");
209        entry.setDocUUID("dummy");
210        entry.setCategory("dummy");
211        entry.setComment("dummy");
212        logs.addLogEntries(Collections.singletonList(entry));
213        return entry;
214    }
215
216    /**
217     * @since 5.9.5
218     */
219    public void clearDummyLogEntries() {
220        PersistenceProviderFactory pf = Framework.getService(PersistenceProviderFactory.class);
221        EntityManager em = pf.newProvider("nxaudit-logs").acquireEntityManager();
222        LogEntryProvider provider = LogEntryProvider.createProvider(em);
223        provider.removeEntries("dummy", null);
224    }
225
226    /**
227     * @since 5.9.5
228     */
229    @Factory(scope = ScopeType.EVENT)
230    public boolean isDummyAuditExists() {
231        AuditReader reader = Framework.getService(AuditReader.class);
232        List<LogEntry> entries = reader.getLogEntriesFor("dummy");
233        return !entries.isEmpty();
234    }
235
236    protected DocumentModel createDummyDoc() {
237        DocumentModel doc = documentManager.createDocumentModel("/", "dummy", "Document");
238        doc = documentManager.createDocument(doc);
239        documentManager.save();
240        return doc;
241    }
242
243    /**
244     * @since 5.9.5
245     */
246    public void clearDummyDoc() {
247        PathRef ref = new PathRef("/dummy");
248        if (documentManager.exists(ref)) {
249            documentManager.removeDocument(ref);
250        }
251    }
252
253    /**
254     * @since 5.9.5
255     */
256    @Factory(scope = ScopeType.EVENT)
257    public boolean isDummyDocExists() {
258        return documentManager.exists(new PathRef("/dummy"));
259    }
260
261    // methods to test concurrency issues
262
263    protected int counter = 0;
264
265    /**
266     * @since 5.8
267     */
268    public String performConcurrentRequestTimeoutException() throws Exception {
269        Thread.sleep(15 * 1000);
270        counter++;
271        return null;
272    }
273
274    public int getCounterValue() {
275        return counter;
276    }
277
278}