001/*
002 * Copyright 2013 Atteo.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.atteo.moonshine.directories;
017
018import java.io.IOException;
019import java.nio.file.Files;
020import java.nio.file.Path;
021import java.nio.file.Paths;
022import java.util.ArrayList;
023import java.util.List;
024import java.util.Properties;
025
026import com.google.common.collect.Iterables;
027
028/**
029 * Manages directory structure of the application.
030 */
031public class DefaultFileAccessor implements FileAccessorFactory {
032    private FileAccessorCommandLineParameters parameters = new FileAccessorCommandLineParameters();
033    private WriteableDirectoryLayout writeableLayout;
034    private List<ReadOnlyDirectoryLayout> readOnlyLayouts = new ArrayList<>();
035    private List<Path> extraConfigDirs = new ArrayList<>();
036    private List<Path> extraDataDirs = new ArrayList<>();
037
038    public DefaultFileAccessor() {
039    }
040
041    @Override
042    public Object getParameters() {
043        return parameters;
044    }
045
046    @Override
047    public void addConfigDir(String path) {
048        extraConfigDirs.add(Paths.get(path));
049    }
050
051    @Override
052    public void addDataDir(String path) {
053        extraDataDirs.add(Paths.get(path));
054    }
055
056    @Override
057    public void setWriteableLayout(WriteableDirectoryLayout writeableLayout) {
058        this.writeableLayout = writeableLayout;
059    }
060
061    @Override
062    public FileAccessor getFileAccessor() throws IOException {
063        final Path configHome;
064        final Path dataHome;
065        final Path cacheHome;
066        final Path logHome;
067        final List<Path> configDirs = new ArrayList<>();
068        final List<Path> dataDirs = new ArrayList<>();
069
070        WriteableDirectoryLayout layout = writeableLayout;
071
072        if (parameters.getHomeDirectory() != null) {
073            layout = new SubdirectoryLayout(Paths.get(parameters.getHomeDirectory()));
074        }
075
076        if (layout == null) {
077            layout = new SubdirectoryLayout((Paths.get("")));
078        }
079
080        if (parameters.getConfigHome() != null) {
081            configHome = Paths.get(parameters.getConfigHome());
082        } else {
083            configHome = layout.getConfigHome();
084        }
085        if (parameters.getDataHome() != null) {
086            dataHome = Paths.get(parameters.getDataHome());
087        } else {
088            dataHome = layout.getDataHome();
089        }
090        if (parameters.getCacheHome() != null) {
091            cacheHome = Paths.get(parameters.getCacheHome());
092        } else {
093            cacheHome = layout.getCacheHome();
094        }
095        if (parameters.getLogHome() != null) {
096            logHome = Paths.get(parameters.getLogHome());
097        } else {
098            logHome = layout.getLogHome();
099        }
100
101        Iterables.addAll(configDirs, layout.getConfigDirs());
102        Iterables.addAll(dataDirs, layout.getDataDirs());
103
104        Iterables.addAll(configDirs, extraConfigDirs);
105        Iterables.addAll(dataDirs, extraDataDirs);
106        for (ReadOnlyDirectoryLayout readOnlyLayout : readOnlyLayouts) {
107            Iterables.addAll(configDirs, readOnlyLayout.getConfigDirs());
108            Iterables.addAll(dataDirs, readOnlyLayout.getDataDirs());
109        }
110
111
112        Files.createDirectories(configHome);
113        Files.createDirectories(dataHome);
114        Files.createDirectories(cacheHome);
115        Files.createDirectories(logHome);
116
117        return new FileAccessor() {
118            private Path getFile(Path home, Iterable<Path> dirs, String fileName) {
119                Path filePath = home.resolve(fileName);
120                if (Files.exists(filePath)) {
121                    return filePath;
122                }
123
124                for (Path path : dirs) {
125                    filePath = path.resolve(fileName);
126                    if (Files.exists(filePath)) {
127                        return filePath;
128                    }
129                }
130                return null;
131            }
132
133            private Iterable<Path> getFiles(Path home, Iterable<Path> dirs, String fileName) {
134                List<Path> files = new ArrayList<>();
135                Path filePath = home.resolve(fileName);
136                if (Files.exists(filePath)) {
137                    files.add(filePath);
138                }
139                for (Path path : dirs) {
140                    filePath = path.resolve(fileName);
141                    if (Files.exists(filePath)) {
142                        files.add(filePath);
143                    }
144                }
145                return files;
146            }
147
148            @Override
149            public Path getConfigFile(String fileName) {
150                return getFile(configHome, configDirs, fileName);
151            }
152
153            @Override
154            public Iterable<Path> getConfigFiles(String fileName) {
155                return getFiles(configHome, configDirs, fileName);
156            }
157
158            @Override
159            public Path getWritebleConfigFile(String fileName) {
160                return configHome.resolve(fileName);
161            }
162
163            @Override
164            public Path getDataFile(String fileName) {
165                return getFile(dataHome, dataDirs, fileName);
166            }
167
168            @Override
169            public Iterable<Path> getDataFiles(String fileName) {
170                return getFiles(configHome, configDirs, fileName);
171            }
172
173            @Override
174            public Path getWriteableDataFile(String fileName) {
175                return dataHome.resolve(fileName);
176            }
177
178            @Override
179            public Path getWriteableCacheFile(String fileName) {
180                return cacheHome.resolve(fileName);
181            }
182
183            @Override
184            public Path getWriteableLogfile(String fileName) {
185                return logHome.resolve(fileName);
186            }
187
188            @Override
189            public Properties getProperties() {
190                Properties properties = new Properties();
191                properties.setProperty("configHome", configHome.toAbsolutePath().toString());
192                properties.setProperty("dataHome", dataHome.toAbsolutePath().toString());
193                properties.setProperty("cacheHome", cacheHome.toAbsolutePath().toString());
194                properties.setProperty("logHome", logHome.toAbsolutePath().toString());
195
196                return properties;
197            }
198        };
199    }
200}