001/*
002 * (C) Copyright 2006-2010 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 */
019package org.nuxeo.connect.update.task.live.commands;
020
021import java.io.File;
022import java.io.IOException;
023import java.util.Arrays;
024import java.util.List;
025import java.util.Map;
026import java.util.stream.Collector;
027import java.util.stream.Collectors;
028
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031import org.nuxeo.connect.update.PackageException;
032import org.nuxeo.connect.update.task.Command;
033import org.nuxeo.connect.update.task.Task;
034import org.nuxeo.connect.update.task.standalone.commands.CompositeCommand;
035import org.nuxeo.connect.update.task.standalone.commands.DeployPlaceholder;
036import org.nuxeo.runtime.api.Framework;
037import org.nuxeo.runtime.reload.ReloadContext;
038import org.nuxeo.runtime.reload.ReloadResult;
039import org.nuxeo.runtime.reload.ReloadService;
040import org.osgi.framework.BundleException;
041
042/**
043 * Deploy a runtime bundle, or a directory containing runtime bundles.
044 * <p>
045 * The inverse of this command is Undeploy.
046 *
047 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
048 */
049public class Deploy extends DeployPlaceholder {
050
051    private static final Log log = LogFactory.getLog(Deploy.class);
052
053    public Deploy() {
054        super();
055    }
056
057    public Deploy(File file) {
058        super(file);
059    }
060
061    /**
062     * @deprecated since 9.3, reload mechanism has changed, keep it for backward compatibility
063     */
064    @Deprecated
065    protected Undeploy deployFile(File file, ReloadService service) throws PackageException {
066        String name = service.getOSGIBundleName(file);
067        if (name == null) {
068            // not an OSGI bundle => ignore
069            return null;
070        }
071        try {
072            service.deployBundle(file, true);
073        } catch (BundleException e) {
074            throw new PackageException("Failed to deploy bundle " + file, e);
075        }
076        return new Undeploy(file);
077    }
078
079    /**
080     * @deprecated since 9.3, reload mechanism has changed, keep it for backward compatibility
081     */
082    @Deprecated
083    protected CompositeCommand deployDirectory(File dir, ReloadService service) throws PackageException {
084        CompositeCommand cmd = new CompositeCommand();
085        File[] files = dir.listFiles();
086        if (files != null) {
087            for (File fileInDir : files) {
088                Command ud = deployFile(fileInDir, service);
089                if (ud != null) {
090                    cmd.addCommand(ud);
091                }
092            }
093        }
094        if (cmd.isEmpty()) {
095            // nothing to rollback
096            return null;
097        }
098        return cmd;
099    }
100
101    @Override
102    protected Command doRun(Task task, Map<String, String> prefs) throws PackageException {
103        if (!file.exists()) {
104            log.warn("Can't deploy file " + file + ". File is missing.");
105            return null;
106        }
107        ReloadService srv = Framework.getService(ReloadService.class);
108        boolean useCompatReload = Framework.isBooleanPropertyTrue(ReloadService.USE_COMPAT_HOT_RELOAD);
109        if (useCompatReload) {
110            return doCompatRun(srv);
111        }
112        if (file.isDirectory()) {
113            return _deployDirectory(file, srv);
114        } else {
115            return _deployFile(file, srv);
116        }
117    }
118
119    /**
120     * @deprecated since 9.3, reload mechanism has changed, keep it for backward compatibility
121     */
122    @Deprecated
123    protected Command doCompatRun(ReloadService srv) throws PackageException {
124        Command rollback;
125        if (file.isDirectory()) {
126            rollback = deployDirectory(file, srv);
127        } else {
128            rollback = deployFile(file, srv);
129        }
130        if (rollback != null) {
131            // some deployments where done
132            try {
133                srv.runDeploymentPreprocessor();
134            } catch (IOException e) {
135                throw new PackageException(e.getMessage(), e);
136            }
137        }
138        return rollback;
139    }
140
141    // TODO change the method name when removing deployFile
142    protected Undeploy _deployFile(File file, ReloadService service) throws PackageException {
143        String name = service.getOSGIBundleName(file);
144        if (name == null) {
145            // not an OSGI bundle => ignore
146            return null;
147        }
148        try {
149            ReloadResult result = service.reloadBundles(new ReloadContext().deploy(file));
150            return result.deployedFilesAsStream().map(Undeploy::new).findFirst().orElseThrow(
151                    () -> new IllegalStateException("Bundle " + file + " wasn't deployed"));
152        } catch (BundleException e) {
153            throw new PackageException("Failed to deploy bundle " + file, e);
154        }
155    }
156
157    // TODO change the method name when removing deployDirectory
158    protected CompositeCommand _deployDirectory(File dir, ReloadService service) throws PackageException {
159        File[] files = dir.listFiles();
160        if (files != null) {
161            List<File> bundles = Arrays.stream(files)
162                                       .filter(f -> service.getOSGIBundleName(f) != null)
163                                       .collect(Collectors.toList());
164            if (bundles.isEmpty()) {
165                // nothing to deploy
166                return null;
167            }
168            try {
169                ReloadResult result = service.reloadBundles(new ReloadContext().deploy(bundles));
170                return result.deployedFilesAsStream().map(Undeploy::new).collect(
171                        Collector.of(CompositeCommand::new, CompositeCommand::addCommand, CompositeCommand::combine));
172            } catch (BundleException e) {
173                throw new PackageException("Failed to deploy bundles " + bundles, e);
174            }
175        }
176        return null;
177    }
178
179}