001/**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one or more
004 * contributor license agreements.  See the NOTICE file distributed with
005 * this work for additional information regarding copyright ownership.
006 * The ASF licenses this file to You under the Apache License, Version 2.0
007 * (the "License"); you may not use this file except in compliance with
008 * the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing, software
013 *  distributed under the License is distributed on an "AS IS" BASIS,
014 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 *  See the License for the specific language governing permissions and
016 *  limitations under the License.
017 */
018package org.apache.xbean.recipe;
019
020/**
021 * Reference is a named (lazy) reference from one object to another. This data class is updated when the reference
022 * is resolved which can be immedately when the ref is created, or later when an instance with the referenced
023 * name is created.
024 * <p/>
025 * When the reference is resolved, an optional Action will be invoked which is commonly used to update a
026 * property on the source object of the reference.
027 */
028public class Reference {
029    private final String name;
030    private boolean resolved;
031    private Object instance;
032    private Action action;
033
034    /**
035     * Create a reference to the specified name.
036     * @param name the name of the referenced object
037     */
038    public Reference(String name) {
039        this.name = name;
040    }
041
042    /**
043     * Gets the name of the referenced object.
044     * @return name the name of the referenced object
045     */
046    public String getName() {
047        return name;
048    }
049
050    /**
051     * Has this reference been resolved?
052     * @return true if the reference has been resolved; false otherwise
053     */
054    public boolean isResolved() {
055        return resolved;
056    }
057
058    /**
059     * Gets the referenced object instance or null if the reference has not been resolved yet;
060     *
061     * @return the referenced object instance or null
062     */
063    public Object get() {
064        return instance;
065    }
066
067    /**
068     * Sets the referenced object instance.  If an action is registered the onSet method is invoked.
069     *
070     * @param object the reference instance
071     */
072    public void set(Object object) {
073        if (resolved) {
074            throw new ConstructionException("Reference has already been resolved");
075        }
076        resolved = true;
077        this.instance = object;
078        if (action != null) {
079            action.onSet(this);
080        }
081    }
082
083    /**
084     * Registers an action to invoke when the instance is set.  If the instance, has already been set, the
085     * onSet method will immedately be invoked.
086     *
087     * @return the action to invoke when this refernce is resolved; not null
088     */
089    public void setAction(Action action) {
090        if (action == null) {
091            throw new NullPointerException("action is null");
092        }
093        this.action = action;
094        if (resolved) {
095            action.onSet(this);
096        }
097    }
098
099    public static interface Action {
100        void onSet(Reference ref);
101    }
102}