package blade.cli.cmds;
import aQute.bnd.osgi.Jar;
import blade.cli.DeployOptions;
import blade.cli.blade;
import blade.cli.jmx.JMXBundleDeployer;
import blade.cli.util.FileWatcher;
import java.io.File;
import java.net.MalformedURLException;
import java.util.Collections;
import java.util.Formatter;
import java.util.List;
import java.util.regex.Pattern;
public class DeployCommand {
private final static Pattern BSN_GUESS = Pattern.compile("\\b\\d+(?:\\.\\d+)*\\b");
final private blade blade;
final private DeployOptions options;
private JMXBundleDeployer _bundleDeployer;
public DeployCommand(blade blade, DeployOptions options) throws Exception {
this.blade = blade;
this.options = options;
List<String> args = options._arguments();
if (args.size() == 0) {
// Default command
printHelp();
}
else {
execute();
}
}
private void addError(String prefix, String msg) {
blade.addErrors(prefix, Collections.singleton(msg));
}
private void deploy(JMXBundleDeployer bundleDeployer, String bsn,
String bundleUrl) throws Exception {
final long bundleId = bundleDeployer.deploy(bsn, bundleUrl);
blade.out().println("Installed or updated bundle " + bundleId);
if (bundleId <= 0) {
addError(
"Deploy", "Unable to deploy bundle to framework " + bundleId);
}
}
private void execute() throws Exception {
int numOfFiles = options._arguments().size();
for (int i = 0; i < numOfFiles; i++) {
String bundlePath = options._arguments().get(i);
File bundleFile = new File(bundlePath);
if (!bundleFile.exists() && !bundleFile.isAbsolute()) {
bundleFile = new File(blade.getBase(), bundlePath);
}
if (bundleFile.exists()) {
String bsn = null;
try (Jar jar = new Jar(bundleFile)) {
bsn = jar.getBsn();
}
if (bsn == null && bundleFile.getName().toLowerCase().endsWith(".war")) {
bsn = guessBsnFromWar(bundleFile);
}
if (bsn == null) {
addError("Deploy", "Unable to determine bsn for file " +
bundleFile.getAbsolutePath());
}
final JMXBundleDeployer bundleDeployer = getBundleDeployer();
String bundleUrl = getBundleUrl(bundleFile);
if (bundleDeployer != null && bundleUrl != null) {
deploy(bundleDeployer, bsn, bundleUrl);
if (options.watch()) {
watch(bundleDeployer, bsn, bundleFile);
}
}
}
else {
addError("Deploy", "Unable to find specified bundle file " +
bundleFile.getAbsolutePath());
}
}
}
private String guessBsnFromWar(File bundleFile) {
return BSN_GUESS.matcher(bundleFile.getName()).replaceAll("")
.replaceAll("\\.war$", "").replaceAll("-$", "");
}
private String getBundleUrl(File bundleFile) throws MalformedURLException {
String bundleUrl = null;
if (bundleFile.toPath().toString().toLowerCase().endsWith(".war")) {
bundleUrl = "webbundle:"
+ bundleFile.toURI().toURL().toExternalForm()
+ "?Web-ContextPath=/" + guessBsnFromWar(bundleFile);
}
else {
bundleUrl = bundleFile.toURI().toURL().toExternalForm();
}
return bundleUrl;
}
private JMXBundleDeployer getBundleDeployer() {
if (_bundleDeployer == null) {
int port = options.port();
JMXBundleDeployer bundleDeployer = null;
try {
if (port > 0) {
bundleDeployer = new JMXBundleDeployer(port);
}
else {
bundleDeployer = new JMXBundleDeployer();
}
}
catch (IllegalArgumentException e) {
addError("Deploy", "Unable to connect to Liferay's OSGi framework");
}
_bundleDeployer = bundleDeployer;
}
return _bundleDeployer;
}
private void printHelp() throws Exception {
Formatter f = new Formatter();
options._command().help(f, this);
blade.out().println(f);
f.close();
}
private void watch(final JMXBundleDeployer bundleDeployer, final String bsn,
final File bundleFile) throws Exception {
final boolean[] deploy = new boolean[1];
new Thread() {
@Override
public void run() {
synchronized (bundleFile) {
while (true) {
try {
bundleFile.wait();
} catch (InterruptedException e) {
}
while (deploy[0]) {
deploy[0] = false;
try {
bundleFile.wait(300);
} catch (InterruptedException e) {
}
}
deploy[0] = false;
try {
String bundleUrl = getBundleUrl(bundleFile);
long bundleId = bundleDeployer.deploy(
bsn, bundleUrl);
blade.out().println("Installed or updated bundle " + bundleId);
} catch (Exception e) {
}
}
}
}
}.start();
new FileWatcher(blade.getBase().toPath(), bundleFile.getAbsoluteFile()
.toPath(), true, new Runnable() {
@Override
public void run() {
synchronized (bundleFile) {
deploy[0] = true;
bundleFile.notify();
}
}
});
}
}