/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.jackrabbit.core;

import java.util.ConcurrentModificationException;

import javax.jcr.InvalidItemStateException;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;

import org.apache.jackrabbit.core.state.NoSuchItemStateException;
import org.apache.jackrabbit.test.AbstractJCRTest;

public class NPEandCMETest extends AbstractJCRTest {

    private final static int NUM_THREADS = 10;
    private final static boolean SHOW_STACKTRACE = true;
    
    protected void setUp() throws Exception {
        super.setUp();
        Session session = getHelper().getSuperuserSession();
        session.getRootNode().addNode("test");
        session.save();
    }
    
    protected void tearDown() throws Exception {
        try {
            Session session = getHelper().getSuperuserSession();
            if (session.getRootNode().hasNode("test")) {
                session.getRootNode().getNode("test").remove();
                session.save();
            }
        } finally {
            super.tearDown();
        }
    }
    
    public void testDo() throws Exception {
        Thread[] threads = new Thread[NUM_THREADS];
        TestTask[] tasks = new TestTask[NUM_THREADS];
        for (int i = 0; i < NUM_THREADS; i++) {
            Session session = getHelper().getSuperuserSession();
            tasks[i] = new TestTask(i, session);
        }
        for (int i = 0; i < NUM_THREADS; i++) {
            threads[i] = new Thread(tasks[i]);
            threads[i].start();
        }
        for (int i = 0; i < NUM_THREADS; i++) {
            threads[i].join();
        }
        int npes = 0, cmes = 0;
        for(int i = 0; i < NUM_THREADS; i++) {
            npes += tasks[i].npes;
            cmes += tasks[i].cmes;
        }
        System.err.println("Total NPEs: " + npes);
        System.err.println("Total CMEs: " + cmes);
    }
    
    private static class TestTask implements Runnable {

        private final Session session;
        private final int id;
        private final Node test;
        
        private int npes = 0;
        private int cmes = 0;
        
        private TestTask(int id, Session session) throws RepositoryException {
            this.id = id;
            this.session = session;
            test = this.session.getRootNode().getNode("test");
        }
        
        public void run() {
            try {
                for (int i = 0; i < 500; i++) {
                    NodeIterator nodes = test.getNodes();
                    if (nodes.getSize() > 100) {
                        long count = nodes.getSize() - 100;
                        while (nodes.hasNext() && count-- > 0) {
                            Node node = nodes.nextNode();
                            if (node != null) {
                                try {
                                    node.remove();
                                }
                                catch (ItemNotFoundException e) {
                                    // item was already removed
                                }
                                catch (InvalidItemStateException e) {
                                    // ignorable
                                }
                            }
                        }
                        session.save();
                    }
                    test.addNode("test-" + id + "-" + i);
                    session.save();
                }
                
            }
            catch (InvalidItemStateException e) {
                // ignorable
            }
            catch (RepositoryException e) {
                if (e.getCause() == null || !(e.getCause() instanceof NoSuchItemStateException)) {
                    System.err.println("thread" + id + ":" + e);
                    e.printStackTrace();
                }
                // else ignorable
            }
            catch (NullPointerException e) {
                System.err.println("====> " + e);
                if (SHOW_STACKTRACE) {
                    e.printStackTrace();
                }
                npes++;
            }
            catch (ConcurrentModificationException e) {
                System.err.println("====> " + e);
                if (SHOW_STACKTRACE) {
                    e.printStackTrace();
                }
                cmes++;
            }
        }
        
    }
}

@@ -1208,61 +1208,242 @@
 st;%0A
-%0Apublic class NPEandCMETest extends AbstractJCRTest %7B
+import org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;%0A%0Apublic class NPEandCMETest extends AbstractJCRTest %7B%0A%0A    /** Logger instance */%0A    private static final Logger log =%0A            LoggerFactory.getLogger(NPEandCMETest.class);
 %0A%0A  
@@ -2842,34 +2842,28 @@
         
-System.err.println
+assertEquals
 (%22Total 
@@ -2866,21 +2866,25 @@
 tal NPEs
-: %22 +
+ %3E 0%22, 0,
  npes);%0A
@@ -2891,34 +2891,28 @@
         
-System.err.println
+assertEquals
 (%22Total 
@@ -2919,13 +2919,17 @@
 CMEs
-: %22 +
+ %3E 0%22, 0,
  cme
@@ -4693,50 +4693,67 @@
     
-if (e.getCause() == null %7C%7C !(e.getC
+Throwable cause = e.getCause();%0A                if (!(c
 ause
-()
  ins
@@ -4813,91 +4813,59 @@
     
-System.err.println(%22thread%22 + id + %22:%22 + e);%0A                    e.printStackTrace(
+log.warn(%22Unexpected RepositoryException caught%22, e
 );%0A 
@@ -4994,381 +4994,173 @@
     
-System.err.println(%22====%3E %22 + e);%0A                if (SHOW_STACKTRACE) %7B%0A                    e.printStackTrace();%0A                %7D%0A                npes++;%0A            %7D%0A            catch (ConcurrentModificationException e) %7B%0A                System.err.println(%22====%3E %22 + e);%0A                if (SHOW_STACKTRACE) %7B%0A                    e.printStackTrace();%0A                %7D
+log.error(%22NPE caught%22, e);%0A                npes++;%0A            %7D%0A            catch (ConcurrentModificationException e) %7B%0A                log.error(%22CME caught%22, e);
 %0A   

JCR-3063 NullPointerException in ItemManager