001    /**
002     * planningtool - A Planning Tool with Critiquing Support.
003     * 
004     * Copyright (C) 2006 olale
005    
006     * This program is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU General Public License
008     * as published by the Free Software Foundation; either version 2
009     * of the License, or (at your option) any later version.
010    
011     * This program is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014     * GNU General Public License for more details.
015    
016     * You should have received a copy of the GNU General Public License
017     * along with this program; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019    
020     * Contact information: 
021     * E-mail: olale@ida.liu.se
022     *         olale@lysator.liu.se
023     */
024    package se.liu.ida.critiquer.activities.parameters;
025    
026    import java.io.Serializable;
027    import java.util.concurrent.Semaphore;
028    
029    import se.liu.ida.critiquer.activities.Activity;
030    
031    /**
032     * This class describes the parameters that describe an activity
033     * 
034     * When creating a plan, we start by choosing the type of activity 
035     * which in turn gives us a template hierarchy of activities that 
036     * we can start to manipulate
037     * 
038     * This structure contains texttual information on missions and possibly 
039     * time dependencies
040     * 
041     * Next, resources are assigned to missions in the resource view by dragging 
042     * resources to missions
043     * 
044     * When this is done, time intervals for each mission can be calculated in 
045     * the time view, according to one of several preconfigured settings (launch 
046     * missions immediately after one another, set certain time slacks)
047     * 
048     *  Therefore, an activity parameter has a view associated with it where one
049     *  can configure the parameter
050     * 
051     * */
052    public abstract class ActivityParameter<T> implements Parameter<T>, Serializable {
053    
054            protected T value = null;
055            protected T oldValue = null;
056            /**
057             * If the user has ever set the value of this parameter, this will be true, otherwise false.
058             */
059            protected boolean hasBeenSet = false;
060            
061            private Activity activity;
062            private Semaphore valueUpdate = new Semaphore(1,true);
063            protected String name;
064    
065            /**
066             * @param activity
067             */
068            public ActivityParameter(String name, Activity activity) {
069                    this.activity = activity;
070                    this.name = name;
071            }
072    
073            public abstract String toString();
074    
075            /**
076             * @return Returns the value.
077             */
078            public T getValue() {
079                    return value;
080            }
081    
082            public boolean hasValue() {
083                    return value!=null && hasBeenSet;
084            }
085            
086            /**
087             * This method can be used directly by subclasses if the parameter value
088             * reference remaing the same but there has been changes to the value so
089             * listeners should be notified
090             * 
091             * Also, we create a new thread to do the updating here since this may be
092             * called during the process of updating a parameter.
093             * 
094             * 
095             */
096    
097            protected void valueChanged() {
098                    new Thread("\""+activity+"\":\""+name+"\" update thread") {
099                            
100                            @Override
101                            public void run() {
102                                    activity.signalParamChanged(ActivityParameter.this);
103                                    valueUpdate.release();
104                            }
105    
106                    }.start();
107    
108            }
109    
110            /**
111             * 
112             * Update the value of this parameter iff the value is consistent for this parameter
113             * The updating is performed with a binary semaphore set so that there can be no more than one thread updating and signalling activities of a value update 
114             * 
115             * @param value
116             *            The value to set. Sets a value and notifies all listeners
117             * @return true if the change was consistent, false otherwise.
118             */
119            public synchronized boolean setValue(T value) {
120                    boolean consistent = false;
121                    try {
122                            valueUpdate.acquire();
123                            consistent = Activity.isConsistent(getActivity(), this, value);
124                            if (consistent) {
125                                    oldValue = this.value;
126                                    this.value = value;
127                                    hasBeenSet=true;
128                                    valueChanged();
129                            }
130                            
131                    } catch (InterruptedException e) {
132                            System.err.println(name+".setValue interrupted");
133                            valueUpdate.release();
134                    }
135                    return consistent;
136            }
137    
138            /**
139             * @return Returns the name.
140             */
141            public String getName() {
142                    return name;
143            }
144    
145            /**
146             * @param name
147             *            The name to set.
148             */
149            void setName(String name) {
150                    this.name = name;
151            }
152    
153            /**
154             * @return Returns the activity.
155             */
156            public Activity getActivity() {
157                    return activity;
158            }
159    
160            /**
161             * @return Returns the oldValue.
162             */
163            public T getOldValue() {
164                    return oldValue;
165            }
166    
167    }