2 * jSite2 - ProjectManager.java -
3 * Copyright © 2008 David Roden
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 package net.pterodactylus.jsite.project;
22 import java.beans.PropertyChangeEvent;
23 import java.beans.PropertyChangeListener;
25 import java.io.FileInputStream;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.OutputStream;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.Properties;
34 import java.util.Random;
35 import java.util.Map.Entry;
36 import java.util.logging.Level;
37 import java.util.logging.Logger;
39 import net.pterodactylus.jsite.core.JSiteException;
40 import net.pterodactylus.jsite.core.NodeManager;
41 import net.pterodactylus.util.io.Closer;
42 import net.pterodactylus.util.logging.Logging;
43 import net.pterodactylus.util.number.Hex;
46 * Manages projects, taking care of persistence, lifetime statistics, and other
49 * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
51 public class ProjectManager implements PropertyChangeListener {
54 private static final Logger logger = Logging.getLogger(ProjectManager.class.getName());
56 /** The RNG used to create project IDs. */
57 private static final Random random = new Random();
59 /** The directory the projects are stored in. */
60 private final String directory;
62 /** The node manager. */
63 private NodeManager nodeManager;
66 private final List<Project> projects = Collections.synchronizedList(new ArrayList<Project>());
69 * Creates a new project manager that saves and restores its state to/from
70 * the given directory.
73 * The directory to save and restore states to/from
75 public ProjectManager(String directory) {
76 this.directory = directory;
84 * Returns the directory the projects are loaded from and saved to.
86 * @return The directory for storing the projects
88 public String getDirectory() {
93 * Returns a list of all projects.
95 * @return A list of all projects
97 public List<Project> getProjects() {
98 return Collections.unmodifiableList(new ArrayList<Project>(projects));
102 * Sets the node manager to use.
105 * The node manager to use
107 public void setNodeManager(NodeManager nodeManager) {
108 this.nodeManager = nodeManager;
116 * Loads projects and statistics.
118 * @throws IOException
119 * if an I/O error occurs
121 public void load() throws IOException {
122 File directoryFile = new File(directory);
123 File projectFile = new File(directoryFile, "projects.properties");
124 if (!projectFile.exists() || !projectFile.isFile() || !projectFile.canRead()) {
127 Properties projectProperties = new Properties();
128 InputStream projectInputStream = null;
130 projectInputStream = new FileInputStream(projectFile);
131 projectProperties.load(projectInputStream);
133 Closer.close(projectInputStream);
135 int projectIndex = 0;
136 while (projectProperties.containsKey("projects." + projectIndex + ".name")) {
137 String projectPrefix = "projects." + projectIndex;
138 String projectId = projectProperties.getProperty(projectPrefix + ".id");
139 String projectName = projectProperties.getProperty(projectPrefix + ".name");
140 String projectDescription = projectProperties.getProperty(projectPrefix + ".description");
141 String projectPrivateKey = projectProperties.getProperty(projectPrefix + ".privateKey");
142 String projectPublicKey = projectProperties.getProperty(projectPrefix + ".publicKey");
143 String projectBasePath = projectProperties.getProperty(projectPrefix + ".basePath");
144 String projectDefaultFile = projectProperties.getProperty(projectPrefix + ".defaultFile");
145 Project project = new Project();
146 project.setId(projectId);
147 project.setName(projectName);
148 project.setDescription(projectDescription);
149 project.setPrivateKey(projectPrivateKey);
150 project.setPublicKey(projectPublicKey);
151 project.setBasePath(projectBasePath);
152 project.setDefaultFile(projectDefaultFile);
153 int overrideIndex = 0;
154 while (projectProperties.containsKey(projectPrefix + ".overrides." + overrideIndex + ".override")) {
155 String filePath = projectProperties.getProperty(projectPrefix + ".overrides." + overrideIndex + ".filePath");
156 FileOverride override = FileOverride.valueOf(projectProperties.getProperty(projectPrefix + ".overrides." + overrideIndex + ".override"));
157 project.addFileOverride(filePath, override);
158 logger.log(Level.FINEST, "read override: " + filePath + ", " + override);
161 projects.add(project);
162 logger.fine("loaded project “" + project.getName() + "”.");
168 * Saves projects and statistics.
170 * @throws IOException
171 * if an I/O error occurs
173 public void save() throws IOException {
174 File directoryFile = new File(directory);
175 if (!directoryFile.exists()) {
176 if (!directoryFile.mkdirs()) {
177 throw new IOException("could not create directory: " + directory);
180 Properties projectProperties = new Properties();
181 int projectIndex = 0;
182 for (Project project : projects) {
183 String projectPrefix = "projects." + projectIndex;
184 projectProperties.setProperty(projectPrefix + ".id", project.getId());
185 projectProperties.setProperty(projectPrefix + ".name", project.getName());
186 projectProperties.setProperty(projectPrefix + ".description", project.getDescription());
187 projectProperties.setProperty(projectPrefix + ".privateKey", project.getPrivateKey());
188 projectProperties.setProperty(projectPrefix + ".publicKey", project.getPublicKey());
189 projectProperties.setProperty(projectPrefix + ".basePath", project.getBasePath());
190 projectProperties.setProperty(projectPrefix + ".defaultFile", project.getDefaultFile());
191 int overrideIndex = 0;
192 for (Entry<String, FileOverride> overrideEntry : project.getFileOverrides().entrySet()) {
193 projectProperties.setProperty(projectPrefix + ".overrides." + overrideIndex + ".filePath", overrideEntry.getKey());
194 projectProperties.setProperty(projectPrefix + ".overrides." + overrideIndex + ".override", overrideEntry.getValue().toString());
199 File projectFile = new File(directoryFile, "projects.properties");
200 OutputStream projectOutputStream = null;
202 projectOutputStream = new FileOutputStream(projectFile);
203 projectProperties.store(projectOutputStream, "jSite projects");
205 Closer.close(projectOutputStream);
210 * Creates a new project. The returned {@link Project} will contain a newly
211 * generated key pair.
213 * @return A newly created project
214 * @throws IOException
215 * if an I/O error occured communicating with the node
216 * @throws JSiteException
217 * if there is a problem with the node
219 public Project createProject() throws IOException, JSiteException {
220 Project project = new Project();
221 String[] keyPair = nodeManager.generateKeyPair();
222 project.setId(generateId());
224 project.setDescription("");
225 project.setPrivateKey(keyPair[0]);
226 project.setPublicKey(keyPair[1]);
227 project.setBasePath("");
228 project.setDefaultFile("");
229 projects.add(project);
230 project.addPropertyChangeListener(this);
233 } catch (IOException ioe1) {
240 * Clones the given project and returns the clone. The clone will be
241 * identical in all user-exposed fields, except for the project’s
242 * {@link Project#getId ID}.
245 * The project to clone
246 * @return The cloned project
248 public Project cloneProject(Project project) {
249 Project projectClone = new Project(project);
250 projects.add(projectClone);
251 projectClone.setId(generateId());
252 projectClone.addPropertyChangeListener(this);
255 } catch (IOException ioe1) {
262 * Removes the given project.
265 * The project to remove
267 public void removeProject(Project project) {
268 projects.remove(project);
271 } catch (IOException ioe1) {
281 * Generates a new random ID, consisting of 16 random bytes converted to a
282 * hexadecimal number.
286 private static String generateId() {
287 byte[] idBytes = new byte[16];
288 random.nextBytes(idBytes);
289 return Hex.toHex(idBytes);
293 // INTERFACE PropertyChangeListener
299 public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
302 } catch (IOException ioe1) {