001 /* 002 * JBoss, Home of Professional Open Source. 003 * Copyright 2008, Red Hat Middleware LLC, and individual contributors 004 * as indicated by the @author tags. See the copyright.txt file in the 005 * distribution for a full listing of individual contributors. 006 * 007 * This is free software; you can redistribute it and/or modify it 008 * under the terms of the GNU Lesser General Public License as 009 * published by the Free Software Foundation; either version 2.1 of 010 * the License, or (at your option) any later version. 011 * 012 * This software is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this software; if not, write to the Free 019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 021 */ 022 023 package org.jboss.dna.common.monitor; 024 025 import java.util.Locale; 026 import java.util.concurrent.atomic.AtomicBoolean; 027 import java.util.concurrent.locks.ReadWriteLock; 028 import java.util.concurrent.locks.ReentrantReadWriteLock; 029 import net.jcip.annotations.GuardedBy; 030 import org.jboss.dna.common.collection.Problems; 031 import org.jboss.dna.common.collection.SimpleProblems; 032 import org.jboss.dna.common.i18n.I18n; 033 034 /** 035 * A basic progress monitor. 036 * <p> 037 * This class is thread-safe except when accessing or adding {@link #getProblems() problems}. Problems must only be added by the 038 * {@link ProgressMonitor <strong>Updater</strong>}, and accessed by {@link ProgressMonitor Observers} only after the activity 039 * has been {@link #done() completed}. 040 * </p> 041 * 042 * @author Randall Hauch 043 * @author John Verhaeg 044 */ 045 public class SimpleProgressMonitor implements ProgressMonitor { 046 047 @GuardedBy( "lock" ) 048 private I18n taskName; 049 @GuardedBy( "lock" ) 050 private Object[] taskNameParams; 051 @GuardedBy( "lock" ) 052 private double totalWork; 053 @GuardedBy( "lock" ) 054 private double worked; 055 056 private final String activityName; 057 private final ReadWriteLock lock = new ReentrantReadWriteLock(); 058 private final AtomicBoolean cancelled = new AtomicBoolean(false); 059 private final Problems problems = new SimpleProblems(); 060 061 public SimpleProgressMonitor( String activityName ) { 062 this.activityName = activityName != null ? activityName.trim() : ""; 063 this.taskName = null; 064 this.taskNameParams = null; 065 } 066 067 /** 068 * {@inheritDoc} 069 */ 070 public String getActivityName() { 071 return this.activityName; 072 } 073 074 /** 075 * {@inheritDoc} 076 */ 077 public void beginTask( double totalWork, 078 I18n name, 079 Object... params ) { 080 assert totalWork > 0; 081 try { 082 this.lock.writeLock().lock(); 083 this.taskName = name; 084 this.taskNameParams = params; 085 this.totalWork = totalWork; 086 this.worked = 0.0d; 087 } finally { 088 this.lock.writeLock().unlock(); 089 } 090 } 091 092 /** 093 * {@inheritDoc} 094 */ 095 public ProgressMonitor createSubtask( double subtaskWork ) { 096 return new SubProgressMonitor(this, subtaskWork); 097 } 098 099 /** 100 * <p> 101 * {@inheritDoc} 102 * </p> 103 * 104 * @see org.jboss.dna.common.monitor.ProgressMonitor#done() 105 */ 106 public void done() { 107 boolean alreadyDone = false; 108 try { 109 this.lock.writeLock().lock(); 110 if (this.worked < this.totalWork) { 111 this.worked = this.totalWork; 112 } else { 113 alreadyDone = true; 114 } 115 } finally { 116 this.lock.writeLock().unlock(); 117 } 118 if (!alreadyDone) notifyProgress(); 119 } 120 121 /** 122 * {@inheritDoc} 123 */ 124 public boolean isCancelled() { 125 return this.cancelled.get(); 126 } 127 128 /** 129 * {@inheritDoc} 130 * 131 * @see org.jboss.dna.common.monitor.ProgressMonitor#isDone() 132 */ 133 public boolean isDone() { 134 lock.readLock().lock(); 135 try { 136 return worked >= totalWork; 137 } finally { 138 lock.readLock().unlock(); 139 } 140 } 141 142 /** 143 * {@inheritDoc} 144 */ 145 public void setCancelled( boolean value ) { 146 this.cancelled.set(value); 147 } 148 149 /** 150 * {@inheritDoc} 151 */ 152 public void worked( double work ) { 153 if (work > 0) { 154 try { 155 this.lock.writeLock().lock(); 156 if (this.worked < this.totalWork) { 157 this.worked += work; 158 if (this.worked > this.totalWork) this.worked = this.totalWork; 159 } 160 } finally { 161 this.lock.writeLock().unlock(); 162 } 163 notifyProgress(); 164 } 165 } 166 167 /** 168 * {@inheritDoc} 169 */ 170 public ProgressStatus getStatus( Locale locale ) { 171 try { 172 this.lock.readLock().lock(); 173 String localizedTaskName = this.taskName == null ? "" : this.taskName.text(locale, this.taskNameParams); 174 return new ProgressStatus(this.getActivityName(), localizedTaskName, this.worked, this.totalWork, this.isCancelled()); 175 } finally { 176 this.lock.readLock().unlock(); 177 } 178 } 179 180 /** 181 * Method that is called in {@link #worked(double)} (which is called by {@link #createSubtask(double) subtasks}) when there 182 * has been some positive work, or when the monitor is first marked as {@link #done()}. 183 * <p> 184 * This method implementation does nothing, but subclasses can easily override this method if they want to be updated with the 185 * latest progress. 186 * </p> 187 */ 188 protected void notifyProgress() { 189 // do nothing 190 } 191 192 /** 193 * {@inheritDoc} 194 * <p> 195 * Problems must only be added by the {@link ProgressMonitor <strong>Updater</strong>}, and accessed by 196 * {@link ProgressMonitor Observers} only after the activity has been {@link #done() completed}. 197 * </p> 198 * 199 * @see org.jboss.dna.common.monitor.ProgressMonitor#getProblems() 200 */ 201 public Problems getProblems() { 202 return problems; 203 } 204 }