org.t2framework.commons.util.LazyLoadingReference.java Source code

Java tutorial

Introduction

Here is the source code for org.t2framework.commons.util.LazyLoadingReference.java

Source

    /*
     * Copyright 2008-2010 the T2 Project ant the Others.
     *
     * 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 org.t2framework.commons.util;

import java.lang.ref.WeakReference;
    import java.util.concurrent.Callable;
    import java.util.concurrent.CancellationException;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.Future;
    import java.util.concurrent.FutureTask;
    import java.util.concurrent.atomic.AtomicReference;

public class LazyLoadingReference<T> {

   protected Factory<T> factory;

   protected AtomicReference<WeakReference<Future<T>>> reference = new AtomicReference<WeakReference<Future<T>>>();

   public LazyLoadingReference(Factory<T> factory) {
      this.factory = factory;
   }

   public T get() throws IllegalStateException {
      while (true) {
         WeakReference<Future<T>> ref = reference.get();
         boolean valid = true;
         if (ref == null) {
            FutureTask<T> f = new FutureTask<T>(new Callable<T>() {
               @Override
               public T call() throws Exception {
                  return factory.create();
               }
            });
            ref = new WeakReference<Future<T>>(f);
            if (valid = reference.compareAndSet(null, ref)) {
               f.run();
            }
         }
         if (valid) {
            try {
               Future<T> f = ref.get();
               if (f != null) {
                  return f.get();
               } else {
                  reference.compareAndSet(ref, null);
               }
            } catch (CancellationException e) {
               reference.compareAndSet(ref, null);
            } catch (ExecutionException e) {
               throw new IllegalStateException(e.getCause());
            } catch (Exception e) {
               throw new IllegalStateException(e);
            }
         }
      }
   }

   public interface Factory<T> {
      T create() throws CancellationException, Exception;
   }
}-------------------------
    /*
     * Copyright 2008-2009 the T2 Project ant the Others.
     *
     * 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 org.t2framework.commons.util;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    import java.util.concurrent.CancellationException;

    import org.t2framework.commons.cache.Cache;
    import org.t2framework.commons.cache.CacheFactory;
    import org.t2framework.commons.cache.CacheType;

    import junit.framework.TestCase;

    public class LazyLoadingReferenceTest extends TestCase {

        public void test_loadSimple() throws Exception {
            LazyLoadingReference<String> target = new LazyLoadingReference<String>(
                    new LazyLoadingReference.Factory<String>() {
                        public String create() {
                            return "hoge";
                        }
                    });
            assertEquals("hoge", target.get());
        }

        public void test_loadSimple2() throws Exception {
            LazyLoadingReference<Cache<String, String>> t2 = new LazyLoadingReference<Cache<String, String>>(
                    new LazyLoadingReference.Factory<Cache<String, String>>() {

                        @Override
                        public Cache<String, String> create() throws CancellationException {
                            Cache<String, String> c = CacheFactory.createCache(CacheType.DEFAULT);
                            c.put("aaa", "bbb");
                            return c;
                        }
                    });
            Cache<String, String> cache = t2.get();
            assertNotNull(cache);
            assertNotNull(cache.get("aaa"));

        }

        public void test_exception() throws Exception {
            final Exception e = new Exception();
            LazyLoadingReference<String> target = new LazyLoadingReference<String>(
                    new LazyLoadingReference.Factory<String>() {
                        public String create() throws Exception {
                            throw e;
                        }
                    });
            try {
                target.get();
                fail();
            } catch (IllegalStateException t) {
                assertNotNull(t.getCause());
                assertTrue(t.getCause().getClass() == Exception.class);
                assertEquals(e, t.getCause());
            }
        }

        public void test_loadHeavy() throws Exception {
            final LazyLoadingReference<String> target = new LazyLoadingReference<String>(
                    new LazyLoadingReference.Factory<String>() {
                        public String create() {
                            return "hoge";
                        }
                    });
            final Random random = new Random(System.currentTimeMillis());
            List<Thread> list = new ArrayList<Thread>();
            for (int i = 0; i < 20; i++) {
                Runnable r = new Runnable() {
                    public void run() {
                        try {
                            long l = random.nextLong() % 100;
                            Thread.sleep(l < 0 ? l * -1 : l);
                            assertEquals("hoge", target.get());
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };
                Thread t = new Thread(r);
                list.add(t);
                t.start();
            }
            for (Thread t : list) {
                t.join();
            }
        }
    }