alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (TestSimpleAddRemove.java)

This example Java source code file (TestSimpleAddRemove.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

add_in_listener, add_in_processor, add_in_task, addkind, eventkindcounter, generate\=1\:0, illegalstateexception, ioexception, javactask, net, network, remove_in_listener, remove_in_processor, remove_in_task, removekind, tasklistener, util

The TestSimpleAddRemove.java Java example source code

/*
 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/*
 * @test
 * @bug     7093891
 * @summary support multiple task listeners
 */

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.List;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.TypeElement;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;

import com.sun.source.util.JavacTask;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.tools.javac.api.JavacTool;

public class TestSimpleAddRemove {
    enum AddKind {
        SET_IN_TASK,
        ADD_IN_TASK,
        ADD_IN_PROCESSOR,
        ADD_IN_LISTENER;
    }

    enum RemoveKind {
        REMOVE_IN_TASK,
        REMOVE_IN_PROCESSOR,
        REMOVE_IN_LISTENER,
    }

    enum CompileKind {
        CALL {
            void run(JavacTask t) {
                if (!t.call()) throw new Error("compilation failed");
            }
        },
        GENERATE {
            void run(JavacTask t) throws IOException {
                t.generate();
            }
        };
        abstract void run(JavacTask t) throws IOException;
    }

    static class EventKindCounter extends EnumMap<TaskEvent.Kind, EventKindCounter.Count> {
        static class Count {
            int started;
            int finished;

            @Override
            public String toString() {
                return started + ":" + finished;
            }
        }

        EventKindCounter() {
            super(TaskEvent.Kind.class);
        }

        void inc(TaskEvent.Kind k, boolean started) {
            Count c = get(k);
            if (c == null)
                put(k, c = new Count());

            if (started)
                c.started++;
            else
                c.finished++;
        }
    }

    static class TestListener implements TaskListener {
        EventKindCounter counter;

        TestListener(EventKindCounter c) {
            counter = c;
        }

        public void started(TaskEvent e) {
            counter.inc(e.getKind(), true);
        }

        public void finished(TaskEvent e) {
            counter.inc(e.getKind(), false);
        }
    }

    static void addInListener(final JavacTask task, final TaskEvent.Kind kind, final TaskListener listener) {
        task.addTaskListener(new TaskListener() {
            public void started(TaskEvent e) {
                if (e.getKind() == kind) {
                    task.addTaskListener(listener);
                    task.removeTaskListener(this);
                }
            }

            public void finished(TaskEvent e) { }
        });
    }

    static void removeInListener(final JavacTask task, final TaskEvent.Kind kind, final TaskListener listener) {
        task.addTaskListener(new TaskListener() {
            public void started(TaskEvent e) {
                if (e.getKind() == kind) {
                    task.removeTaskListener(listener);
                    task.removeTaskListener(this);
                }
            }

            public void finished(TaskEvent e) { }
        });
    }

    @SupportedAnnotationTypes("*")
    class TestProcessor extends AbstractProcessor {
        AddKind ak;
        RemoveKind rk;
        TaskListener listener;

        TestProcessor(AddKind ak, RemoveKind rk, TaskListener listener) {
            this.ak = ak;
            this.rk = rk;
            this.listener = listener;
        }

        int round = 0;

        @Override
        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
//            System.err.println("TestProcessor.process " + roundEnv);
            JavacTask task = JavacTask.instance(processingEnv);
            if (++round == 1) {
                switch (ak) {
                    case ADD_IN_PROCESSOR:
                        task.addTaskListener(listener);
                        break;
                    case ADD_IN_LISTENER:
                        addInListener(task, TaskEvent.Kind.ANALYZE, listener);
                        break;
                }
            } else if (roundEnv.processingOver()) {
                switch (rk) {
                    case REMOVE_IN_PROCESSOR:
                        task.removeTaskListener(listener);
                        break;
                    case REMOVE_IN_LISTENER:
                        removeInListener(task, TaskEvent.Kind.GENERATE, listener);
                        break;
                }
            }
            return true;
        }
    }

    static class TestSource extends SimpleJavaFileObject {
        public TestSource() {
            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
        }

        @Override
        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
            return "class Test { }";
        }
    }

    public static void main(String... args) throws Exception {
        new TestSimpleAddRemove().run();
    }

    JavacTool tool = (JavacTool) ToolProvider.getSystemJavaCompiler();
    StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null);

    void run() throws Exception {
        for (CompileKind ck: CompileKind.values()) {
            for (AddKind ak: AddKind.values()) {
                for (RemoveKind rk: RemoveKind.values()) {
                    test(ck, ak, rk);
                }
            }
        }
        if (errors > 0)
            throw new Exception(errors + " errors occurred");
    }

    void test(CompileKind ck, AddKind ak, RemoveKind rk) throws IOException {
        System.err.println("Test: " + ck + " " + ak + " " + rk);

        File tmpDir = new File(ck + "-" + ak + "-" + rk);
        tmpDir.mkdirs();
        fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(tmpDir));

        List<String> options = new ArrayList();
        Iterable<? extends JavaFileObject> files = Arrays.asList(new TestSource());
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        JavacTask task = tool.getTask(pw, fm, null, options, null, files);

        EventKindCounter ec = new EventKindCounter();
        TaskListener listener = new TestListener(ec);
        boolean needProcessor = false;

        switch (ak) {
            case SET_IN_TASK:
                task.setTaskListener(listener);
                break;
            case ADD_IN_TASK:
                task.addTaskListener(listener);
                break;
            case ADD_IN_PROCESSOR:
            case ADD_IN_LISTENER:
                needProcessor = true;
        }

        switch (rk) {
            case REMOVE_IN_TASK:
                task.removeTaskListener(listener);
                break;
            case REMOVE_IN_PROCESSOR:
            case REMOVE_IN_LISTENER:
                needProcessor = true;
        }

        if (needProcessor)
            task.setProcessors(Arrays.asList(new TestProcessor(ak, rk, listener)));

        ck.run(task);
        System.err.println(ec);

        check(ck, ak, rk, ec);

        System.err.println();
    }

    void check(CompileKind ck, AddKind ak, RemoveKind rk, EventKindCounter ec) {
        // All results should be independent of ck, so we can ignore that

        // Quick way to compare expected values of ec, by comparing ec.toString()
        String expect = ec.toString();
        String found;

        switch (ak) {
            // Add/set in task should record all events until the listener is removed
            case SET_IN_TASK:
            case ADD_IN_TASK:
                switch (rk) {
                    case REMOVE_IN_TASK:
                        // Remove will succeed, meaning no events will be recorded
                        found = "{}";
                        break;
                    case REMOVE_IN_PROCESSOR:
                        found = "{PARSE=1:1, ENTER=2:2, ANNOTATION_PROCESSING=1:0, ANNOTATION_PROCESSING_ROUND=2:1}";
                        break;
                    case REMOVE_IN_LISTENER:
                        found = "{PARSE=1:1, ENTER=3:3, ANALYZE=1:1, GENERATE=1:0, ANNOTATION_PROCESSING=1:1, ANNOTATION_PROCESSING_ROUND=2:2}";
                        break;
                    default:
                        throw new IllegalStateException();
                }
                break;

            // "Add in processor" should skip initial PARSE/ENTER events
            case ADD_IN_PROCESSOR:
                switch (rk) {
                    // Remove will fail (too early), so events to end will be recorded
                    case REMOVE_IN_TASK:
                        found = "{ENTER=2:2, ANALYZE=1:1, GENERATE=1:1, ANNOTATION_PROCESSING=0:1, ANNOTATION_PROCESSING_ROUND=1:2}";
                        break;
                    case REMOVE_IN_PROCESSOR:
                        found = "{ENTER=1:1, ANNOTATION_PROCESSING_ROUND=1:1}";
                        break;
                    case REMOVE_IN_LISTENER:
                        found = "{ENTER=2:2, ANALYZE=1:1, GENERATE=1:0, ANNOTATION_PROCESSING=0:1, ANNOTATION_PROCESSING_ROUND=1:2}";
                        break;
                    default:
                        throw new IllegalStateException();
                }
                break;

            // "Add in listener" will occur during "ANALYSE.started" event
            case ADD_IN_LISTENER:
                switch (rk) {
                    // Remove will fail (too early, so events to end will be recorded
                    case REMOVE_IN_TASK:
                    case REMOVE_IN_PROCESSOR:
                        found = "{ANALYZE=0:1, GENERATE=1:1}";
                        break;
                    // Remove will succeed during "GENERATE.finished" event
                    case REMOVE_IN_LISTENER:
                        found = "{ANALYZE=0:1, GENERATE=1:0}";
                        break;
                    default:
                        throw new IllegalStateException();
                }
                break;
            default:
                throw new IllegalStateException();
        }

        if (!found.equals(expect)) {
            System.err.println("Expected: " + expect);
            System.err.println("   Found: " + found);
            error("unexpected value found");
        }
    }

    int errors;

    void error(String message) {
        System.err.println("Error: " + message);
        errors++;
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java TestSimpleAddRemove.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.