001/*
002 * (C) Copyright 2006-2016 Nuxeo SA (http://nuxeo.com/) and others.
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 *
016 * Contributors:
017 *     bstefanescu
018 *     jcarsique
019 *     Yannis JULIENNE
020 */
021package org.nuxeo.connect.update.standalone;
022
023import static java.nio.charset.StandardCharsets.UTF_8;
024
025import java.io.File;
026import java.io.FileInputStream;
027import java.io.FileNotFoundException;
028import java.io.IOException;
029import java.io.InputStream;
030
031import org.apache.commons.io.FileUtils;
032import org.nuxeo.common.xmap.XMap;
033import org.nuxeo.connect.update.LocalPackage;
034import org.nuxeo.connect.update.PackageDependency;
035import org.nuxeo.connect.update.PackageException;
036import org.nuxeo.connect.update.PackageState;
037import org.nuxeo.connect.update.PackageType;
038import org.nuxeo.connect.update.PackageUpdateService;
039import org.nuxeo.connect.update.Validator;
040import org.nuxeo.connect.update.Version;
041import org.nuxeo.connect.update.model.Form;
042import org.nuxeo.connect.update.model.TaskDefinition;
043import org.nuxeo.connect.update.task.Task;
044import org.nuxeo.connect.update.xml.FormsDefinition;
045import org.nuxeo.connect.update.xml.PackageDefinitionImpl;
046import org.nuxeo.connect.update.xml.TaskDefinitionImpl;
047
048/**
049 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
050 */
051public class LocalPackageImpl implements LocalPackage {
052
053    protected String id;
054
055    protected PackageState state = PackageState.UNKNOWN;
056
057    protected LocalPackageData data;
058
059    protected PackageDefinitionImpl def;
060
061    private PackageUpdateService service;
062
063    /**
064     * @deprecated Since 5.8. Use {@link #LocalPackageImpl(File, PackageState, PackageUpdateService)} instead.
065     */
066    @Deprecated
067    public LocalPackageImpl(File file, int state, PackageUpdateService pus) throws PackageException {
068        this(null, file, state, pus);
069    }
070
071    /**
072     * @deprecated Since 5.8. Use {@link #LocalPackageImpl(ClassLoader, File, PackageState, PackageUpdateService)}
073     *             instead.
074     */
075    @Deprecated
076    public LocalPackageImpl(ClassLoader parent, File file, int state, PackageUpdateService pus)
077            throws PackageException {
078        this(parent, file, PackageState.getByValue(state), pus);
079    }
080
081    /**
082     * @since 5.7
083     */
084    public LocalPackageImpl(File file, PackageState state, PackageUpdateService pus) throws PackageException {
085        this(null, file, state, pus);
086    }
087
088    /**
089     * @since 5.8
090     */
091    public LocalPackageImpl(ClassLoader parent, File file, PackageState state, PackageUpdateService pus)
092            throws PackageException {
093        this.state = state;
094        service = pus;
095        XMap xmap = StandaloneUpdateService.getXmap();
096        if (xmap == null) { // for tests
097            xmap = StandaloneUpdateService.createXmap();
098        }
099        try {
100            data = new LocalPackageData(parent, file);
101            try (InputStream in = new FileInputStream(data.getManifest())) {
102                def = (PackageDefinitionImpl) xmap.load(in);
103            }
104        } catch (FileNotFoundException e) {
105            throw new PackageException("Invalid package - no package.xml file found in package " + file.getName());
106        } catch (IOException e) {
107            throw new PackageException("Failed to load package.xml descriptor for package " + file.getName(), e);
108        }
109        id = def.getId();
110    }
111
112    @Deprecated
113    @Override
114    public void setState(int state) {
115        this.state = PackageState.getByValue(state);
116    }
117
118    @Override
119    public void setState(PackageState state) {
120        this.state = state;
121    }
122
123    @Override
124    public LocalPackageData getData() {
125        return data;
126    }
127
128    @Override
129    public File getInstallFile() {
130        return data.getEntry(LocalPackage.INSTALL);
131    }
132
133    @Override
134    public File getUninstallFile() {
135        return data.getEntry(LocalPackage.UNINSTALL);
136    }
137
138    @Override
139    public String getLicenseType() {
140        return def.getLicenseType();
141    }
142
143    @Override
144    public String getLicenseUrl() {
145        return def.getLicenseUrl();
146    }
147
148    @Override
149    public String getLicenseContent() throws PackageException {
150        File file = data.getEntry(LocalPackage.LICENSE);
151        if (file.isFile()) {
152            try {
153                return FileUtils.readFileToString(file, UTF_8);
154            } catch (IOException e) {
155                throw new PackageException("Failed to read license.txt file for package: " + getId());
156            }
157        }
158        return null;
159    }
160
161    @Override
162    public String getClassifier() {
163        return def.getClassifier();
164    }
165
166    @Override
167    public String getDescription() {
168        return def.getDescription();
169    }
170
171    @Override
172    public String getId() {
173        return id;
174    }
175
176    @Override
177    public String getName() {
178        return def.getName();
179    }
180
181    @Override
182    public String getTitle() {
183        return def.getTitle();
184    }
185
186    @Deprecated
187    @Override
188    public int getState() {
189        return state.getValue();
190    }
191
192    @Override
193    public PackageState getPackageState() {
194        return state;
195    }
196
197    @Override
198    public String[] getTargetPlatforms() {
199        return def.getTargetPlatforms();
200    }
201
202    @Override
203    public String getTargetPlatformRange() {
204        return def.getTargetPlatformRange();
205    }
206
207    @Override
208    public String getTargetPlatformName() {
209        return def.getTargetPlatformName();
210    }
211
212    @Override
213    public PackageDependency[] getDependencies() {
214        return def.getDependencies();
215    }
216
217    @Override
218    public PackageDependency[] getOptionalDependencies() {
219        return def.getOptionalDependencies();
220    }
221
222    @Override
223    public PackageDependency[] getConflicts() {
224        return def.getConflicts();
225    }
226
227    @Override
228    public PackageDependency[] getProvides() {
229        return def.getProvides();
230    }
231
232    @Override
233    public PackageType getType() {
234        return def.getType();
235    }
236
237    @Override
238    public Version getVersion() {
239        return def.getVersion();
240    }
241
242    @Override
243    public String getVendor() {
244        return def.getVendor();
245    }
246
247    @Override
248    public boolean isLocal() {
249        return true;
250    }
251
252    @Override
253    public Task getInstallTask() throws PackageException {
254        if (def.getInstaller() == null) {
255            def.setInstaller(new TaskDefinitionImpl(service.getDefaultInstallTaskType(), false));
256        } else if (def.getInstaller().getType() == null) {
257            def.getInstaller().setType(service.getDefaultInstallTaskType());
258        }
259        return getTask(def.getInstaller());
260    }
261
262    @Override
263    public Task getUninstallTask() throws PackageException {
264        if (def.getUninstaller() == null) {
265            def.setUninstaller(new TaskDefinitionImpl(service.getDefaultUninstallTaskType(), false));
266        } else if (def.getUninstaller().getType() == null) {
267            def.getUninstaller().setType(service.getDefaultUninstallTaskType());
268        }
269        return getTask(def.getUninstaller());
270    }
271
272    protected Task getTask(TaskDefinition tdef) throws PackageException {
273        Task task;
274        try {
275            task = (Task) data.loadClass(tdef.getType())
276                              .getConstructor(PackageUpdateService.class)
277                              .newInstance(service);
278        } catch (ReflectiveOperationException e) {
279            throw new PackageException(
280                    "Could not instantiate custom task " + tdef.getType() + " for package " + getId(), e);
281        }
282        task.initialize(this, tdef.getRequireRestart());
283        return task;
284    }
285
286    @Override
287    public Validator getValidator() throws PackageException {
288        if (def.getValidator() != null) {
289            try {
290                return (Validator) data.loadClass(def.getValidator()).getConstructor().newInstance();
291            } catch (ReflectiveOperationException e) {
292                throw new PackageException(
293                        "Could not instantiate custom validator " + def.getValidator() + " for package " + getId(), e);
294            }
295        }
296        return null;
297    }
298
299    public Form[] getForms(String path) throws PackageException {
300        File file = data.getEntry(path);
301        if (file.isFile()) {
302            try (FileInputStream in = new FileInputStream(file)) {
303                FormsDefinition forms = (FormsDefinition) StandaloneUpdateService.getXmap().load(in);
304                return forms.getForms();
305            } catch (IOException e) {
306                throw new PackageException("Failed to load forms file: " + file);
307            }
308        }
309        return null;
310    }
311
312    @Override
313    public Form[] getValidationForms() throws PackageException {
314        return getForms(LocalPackage.VALIDATION_FORMS);
315    }
316
317    @Override
318    public Form[] getInstallForms() throws PackageException {
319        return getForms(LocalPackage.INSTALL_FORMS);
320    }
321
322    @Override
323    public Form[] getUninstallForms() throws PackageException {
324        return getForms(LocalPackage.UNINSTALL_FORMS);
325    }
326
327    @Override
328    public String getTermsAndConditionsContent() throws PackageException {
329        File file = data.getEntry(LocalPackage.TERMSANDCONDITIONS);
330        if (file.isFile()) {
331            try {
332                return FileUtils.readFileToString(file, UTF_8);
333            } catch (IOException e) {
334                throw new PackageException("Failed to read license.txt file for package: " + getId());
335            }
336        }
337        return null;
338    }
339
340    @Override
341    public boolean requireTermsAndConditionsAcceptance() {
342        return def.requireTermsAndConditionsAcceptance();
343    }
344
345    @Override
346    public boolean supportsHotReload() {
347        return def.supportsHotReload();
348    }
349
350    @Override
351    public String toString() {
352        return getId();
353    }
354
355}