You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@twill.apache.org by ch...@apache.org on 2013/12/12 23:00:02 UTC
[20/28] Making maven site works.
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-api/src/main/java/org/apache/twill/api/logging/LogEntry.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/logging/LogEntry.java b/twill-api/src/main/java/org/apache/twill/api/logging/LogEntry.java
new file mode 100644
index 0000000..4995328
--- /dev/null
+++ b/twill-api/src/main/java/org/apache/twill/api/logging/LogEntry.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.api.logging;
+
+/**
+ * Represents a log entry emitted by application.
+ */
+public interface LogEntry {
+
+ /**
+ * Log level.
+ */
+ enum Level {
+ FATAL,
+ ERROR,
+ WARN,
+ INFO,
+ DEBUG,
+ TRACE
+ }
+
+ String getLoggerName();
+
+ String getHost();
+
+ long getTimestamp();
+
+ Level getLogLevel();
+
+ String getSourceClassName();
+
+ String getSourceMethodName();
+
+ String getFileName();
+
+ int getLineNumber();
+
+ String getThreadName();
+
+ String getMessage();
+
+ StackTraceElement[] getStackTraces();
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-api/src/main/java/org/apache/twill/api/logging/LogHandler.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/logging/LogHandler.java b/twill-api/src/main/java/org/apache/twill/api/logging/LogHandler.java
new file mode 100644
index 0000000..afded19
--- /dev/null
+++ b/twill-api/src/main/java/org/apache/twill/api/logging/LogHandler.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.api.logging;
+
+/**
+ *
+ */
+public interface LogHandler {
+
+ void onLog(LogEntry logEntry);
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-api/src/main/java/org/apache/twill/api/logging/PrinterLogHandler.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/logging/PrinterLogHandler.java b/twill-api/src/main/java/org/apache/twill/api/logging/PrinterLogHandler.java
new file mode 100644
index 0000000..71a2bca
--- /dev/null
+++ b/twill-api/src/main/java/org/apache/twill/api/logging/PrinterLogHandler.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.api.logging;
+
+import com.google.common.base.Splitter;
+
+import java.io.PrintWriter;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Formatter;
+import java.util.TimeZone;
+
+/**
+ * A {@link LogHandler} that prints the {@link LogEntry} through a {@link PrintWriter}.
+ */
+public final class PrinterLogHandler implements LogHandler {
+
+ private static final ThreadLocal<DateFormat> DATE_FORMAT = new ThreadLocal<DateFormat>() {
+ @Override
+ protected DateFormat initialValue() {
+ DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss,SSS'Z'");
+ format.setTimeZone(TimeZone.getTimeZone("UTC"));
+ return format;
+ }
+ };
+
+ private final PrintWriter writer;
+ private final Formatter formatter;
+
+ /**
+ * Creates a {@link PrinterLogHandler} which has {@link LogEntry} written to the given {@link PrintWriter}.
+ * @param writer The write that log entries will write to.
+ */
+ public PrinterLogHandler(PrintWriter writer) {
+ this.writer = writer;
+ this.formatter = new Formatter(writer);
+ }
+
+ @Override
+ public void onLog(LogEntry logEntry) {
+ String utc = timestampToUTC(logEntry.getTimestamp());
+
+ formatter.format("%s %-5s %s [%s] [%s] %s:%s(%s:%d) - %s\n",
+ utc,
+ logEntry.getLogLevel().name(),
+ getShortenLoggerName(logEntry.getLoggerName()),
+ logEntry.getHost(),
+ logEntry.getThreadName(),
+ getSimpleClassName(logEntry.getSourceClassName()),
+ logEntry.getSourceMethodName(),
+ logEntry.getFileName(),
+ logEntry.getLineNumber(),
+ logEntry.getMessage());
+ formatter.flush();
+
+ StackTraceElement[] stackTraces = logEntry.getStackTraces();
+ if (stackTraces != null) {
+ for (StackTraceElement stackTrace : stackTraces) {
+ writer.append("\tat ").append(stackTrace.toString());
+ writer.println();
+ }
+ writer.flush();
+ }
+ }
+
+ private String timestampToUTC(long timestamp) {
+ return DATE_FORMAT.get().format(new Date(timestamp));
+ }
+
+ private String getShortenLoggerName(String loggerName) {
+ StringBuilder builder = new StringBuilder();
+ String previous = null;
+ for (String part : Splitter.on('.').split(loggerName)) {
+ if (previous != null) {
+ builder.append(previous.charAt(0)).append('.');
+ }
+ previous = part;
+ }
+ return builder.append(previous).toString();
+ }
+
+ private String getSimpleClassName(String className) {
+ return className.substring(className.lastIndexOf('.') + 1);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-api/src/main/java/org/apache/twill/api/logging/package-info.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/logging/package-info.java b/twill-api/src/main/java/org/apache/twill/api/logging/package-info.java
new file mode 100644
index 0000000..e325c18
--- /dev/null
+++ b/twill-api/src/main/java/org/apache/twill/api/logging/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This package contains class for handling logging events.
+ */
+package org.apache.twill.api.logging;
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-api/src/main/java/org/apache/twill/api/package-info.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/package-info.java b/twill-api/src/main/java/org/apache/twill/api/package-info.java
new file mode 100644
index 0000000..5d9df6b
--- /dev/null
+++ b/twill-api/src/main/java/org/apache/twill/api/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * Classes in this package provides core functionality of the Twill library.
+ */
+package org.apache.twill.api;
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-api/src/main/java/org/apache/twill/internal/DefaultEventHandlerSpecification.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/internal/DefaultEventHandlerSpecification.java b/twill-api/src/main/java/org/apache/twill/internal/DefaultEventHandlerSpecification.java
new file mode 100644
index 0000000..df21400
--- /dev/null
+++ b/twill-api/src/main/java/org/apache/twill/internal/DefaultEventHandlerSpecification.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.internal;
+
+import org.apache.twill.api.EventHandlerSpecification;
+import org.apache.twill.api.EventHandler;
+import org.apache.twill.api.EventHandlerSpecification;
+import org.apache.twill.api.EventHandlerSpecification;
+import com.google.common.collect.ImmutableMap;
+import org.apache.twill.api.EventHandlerSpecification;
+
+import java.util.Map;
+
+/**
+ *
+ */
+public class DefaultEventHandlerSpecification implements EventHandlerSpecification {
+
+ private final String className;
+ private final Map<String, String> configs;
+
+ public DefaultEventHandlerSpecification(String className, Map<String, String> configs) {
+ this.className = className;
+ this.configs = configs;
+ }
+
+ public DefaultEventHandlerSpecification(EventHandler eventHandler) {
+ EventHandlerSpecification spec = eventHandler.configure();
+ this.className = eventHandler.getClass().getName();
+ this.configs = ImmutableMap.copyOf(spec.getConfigs());
+ }
+
+ @Override
+ public String getClassName() {
+ return className;
+ }
+
+ @Override
+ public Map<String, String> getConfigs() {
+ return configs;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-api/src/main/java/org/apache/twill/internal/DefaultLocalFile.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/internal/DefaultLocalFile.java b/twill-api/src/main/java/org/apache/twill/internal/DefaultLocalFile.java
new file mode 100644
index 0000000..e43c0c0
--- /dev/null
+++ b/twill-api/src/main/java/org/apache/twill/internal/DefaultLocalFile.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.internal;
+
+import org.apache.twill.api.LocalFile;
+
+import javax.annotation.Nullable;
+import java.net.URI;
+
+/**
+ * A straightforward implementation of {@link LocalFile}.
+ */
+public final class DefaultLocalFile implements LocalFile {
+
+ private final String name;
+ private final URI uri;
+ private final long lastModified;
+ private final long size;
+ private final boolean archive;
+ private final String pattern;
+
+ public DefaultLocalFile(String name, URI uri, long lastModified,
+ long size, boolean archive, @Nullable String pattern) {
+ this.name = name;
+ this.uri = uri;
+ this.lastModified = lastModified;
+ this.size = size;
+ this.archive = archive;
+ this.pattern = pattern;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public URI getURI() {
+ return uri;
+ }
+
+ @Override
+ public long getLastModified() {
+ return lastModified;
+ }
+
+ @Override
+ public long getSize() {
+ return size;
+ }
+
+ @Override
+ public boolean isArchive() {
+ return archive;
+ }
+
+ @Override
+ public String getPattern() {
+ return pattern;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-api/src/main/java/org/apache/twill/internal/DefaultResourceReport.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/internal/DefaultResourceReport.java b/twill-api/src/main/java/org/apache/twill/internal/DefaultResourceReport.java
new file mode 100644
index 0000000..c4c8a29
--- /dev/null
+++ b/twill-api/src/main/java/org/apache/twill/internal/DefaultResourceReport.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.internal;
+
+import org.apache.twill.api.ResourceReport;
+import org.apache.twill.api.TwillRunResources;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Implementation of {@link org.apache.twill.api.ResourceReport} with some
+ * additional methods for maintaining the report.
+ */
+public final class DefaultResourceReport implements ResourceReport {
+ private final SetMultimap<String, TwillRunResources> usedResources;
+ private final TwillRunResources appMasterResources;
+ private final String applicationId;
+
+ public DefaultResourceReport(String applicationId, TwillRunResources masterResources) {
+ this.applicationId = applicationId;
+ this.appMasterResources = masterResources;
+ this.usedResources = HashMultimap.create();
+ }
+
+ public DefaultResourceReport(String applicationId, TwillRunResources masterResources,
+ Map<String, Collection<TwillRunResources>> resources) {
+ this.applicationId = applicationId;
+ this.appMasterResources = masterResources;
+ this.usedResources = HashMultimap.create();
+ for (Map.Entry<String, Collection<TwillRunResources>> entry : resources.entrySet()) {
+ this.usedResources.putAll(entry.getKey(), entry.getValue());
+ }
+ }
+
+ /**
+ * Add resources used by an instance of the runnable.
+ *
+ * @param runnableName name of runnable.
+ * @param resources resources to add.
+ */
+ public void addRunResources(String runnableName, TwillRunResources resources) {
+ usedResources.put(runnableName, resources);
+ }
+
+ /**
+ * Remove the resource corresponding to the given runnable and container.
+ *
+ * @param runnableName name of runnable.
+ * @param containerId container id of the runnable.
+ */
+ public void removeRunnableResources(String runnableName, String containerId) {
+ TwillRunResources toRemove = null;
+ // could be faster if usedResources was a Table, but that makes returning the
+ // report a little more complex, and this does not need to be terribly fast.
+ for (TwillRunResources resources : usedResources.get(runnableName)) {
+ if (resources.getContainerId().equals(containerId)) {
+ toRemove = resources;
+ break;
+ }
+ }
+ usedResources.remove(runnableName, toRemove);
+ }
+
+ /**
+ * Get all the run resources being used by all instances of the specified runnable.
+ *
+ * @param runnableName the runnable name.
+ * @return resources being used by all instances of the runnable.
+ */
+ @Override
+ public Collection<TwillRunResources> getRunnableResources(String runnableName) {
+ return usedResources.get(runnableName);
+ }
+
+ /**
+ * Get all the run resources being used across all runnables.
+ *
+ * @return all run resources used by all instances of all runnables.
+ */
+ @Override
+ public Map<String, Collection<TwillRunResources>> getResources() {
+ return Multimaps.unmodifiableSetMultimap(usedResources).asMap();
+ }
+
+ /**
+ * Get the resources application master is using.
+ *
+ * @return resources being used by the application master.
+ */
+ @Override
+ public TwillRunResources getAppMasterResources() {
+ return appMasterResources;
+ }
+
+ /**
+ * Get the id of the application master.
+ *
+ * @return id of the application master.
+ */
+ @Override
+ public String getApplicationId() {
+ return applicationId;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-api/src/main/java/org/apache/twill/internal/DefaultResourceSpecification.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/internal/DefaultResourceSpecification.java b/twill-api/src/main/java/org/apache/twill/internal/DefaultResourceSpecification.java
new file mode 100644
index 0000000..1327ce5
--- /dev/null
+++ b/twill-api/src/main/java/org/apache/twill/internal/DefaultResourceSpecification.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.internal;
+
+import org.apache.twill.api.ResourceSpecification;
+
+/**
+ * Straightforward implementation of {@link org.apache.twill.api.ResourceSpecification}.
+ */
+public final class DefaultResourceSpecification implements ResourceSpecification {
+ private final int virtualCores;
+ private final int memorySize;
+ private final int instances;
+ private final int uplink;
+ private final int downlink;
+
+ public DefaultResourceSpecification(int virtualCores, int memorySize, int instances, int uplink, int downlink) {
+ this.virtualCores = virtualCores;
+ this.memorySize = memorySize;
+ this.instances = instances;
+ this.uplink = uplink;
+ this.downlink = downlink;
+ }
+
+ @Deprecated
+ @Override
+ public int getCores() {
+ return virtualCores;
+ }
+
+ @Override
+ public int getVirtualCores() {
+ return virtualCores;
+ }
+
+ @Override
+ public int getMemorySize() {
+ return memorySize;
+ }
+
+ @Override
+ public int getInstances() {
+ return instances;
+ }
+
+ @Override
+ public int getUplink() {
+ return uplink;
+ }
+
+ @Override
+ public int getDownlink() {
+ return downlink;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-api/src/main/java/org/apache/twill/internal/DefaultRuntimeSpecification.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/internal/DefaultRuntimeSpecification.java b/twill-api/src/main/java/org/apache/twill/internal/DefaultRuntimeSpecification.java
new file mode 100644
index 0000000..c4f496e
--- /dev/null
+++ b/twill-api/src/main/java/org/apache/twill/internal/DefaultRuntimeSpecification.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.internal;
+
+import org.apache.twill.api.LocalFile;
+import org.apache.twill.api.ResourceSpecification;
+import org.apache.twill.api.RuntimeSpecification;
+import org.apache.twill.api.TwillRunnableSpecification;
+import com.google.common.collect.ImmutableList;
+
+import java.util.Collection;
+
+/**
+ * Straightforward implementation of {@link RuntimeSpecification}.
+ */
+public final class DefaultRuntimeSpecification implements RuntimeSpecification {
+
+ private final String name;
+ private final TwillRunnableSpecification runnableSpec;
+ private final ResourceSpecification resourceSpec;
+ private final Collection<LocalFile> localFiles;
+
+ public DefaultRuntimeSpecification(String name,
+ TwillRunnableSpecification runnableSpec,
+ ResourceSpecification resourceSpec,
+ Collection<LocalFile> localFiles) {
+ this.name = name;
+ this.runnableSpec = runnableSpec;
+ this.resourceSpec = resourceSpec;
+ this.localFiles = ImmutableList.copyOf(localFiles);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public TwillRunnableSpecification getRunnableSpecification() {
+ return runnableSpec;
+ }
+
+ @Override
+ public ResourceSpecification getResourceSpecification() {
+ return resourceSpec;
+ }
+
+ @Override
+ public Collection<LocalFile> getLocalFiles() {
+ return localFiles;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillRunResources.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillRunResources.java b/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillRunResources.java
new file mode 100644
index 0000000..bd8f8f5
--- /dev/null
+++ b/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillRunResources.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.internal;
+
+import org.apache.twill.api.TwillRunResources;
+
+/**
+ * Straightforward implementation of {@link org.apache.twill.api.TwillRunResources}.
+ */
+public class DefaultTwillRunResources implements TwillRunResources {
+ private final String containerId;
+ private final int instanceId;
+ private final int virtualCores;
+ private final int memoryMB;
+ private final String host;
+
+ public DefaultTwillRunResources(int instanceId, String containerId,
+ int cores, int memoryMB, String host) {
+ this.instanceId = instanceId;
+ this.containerId = containerId;
+ this.virtualCores = cores;
+ this.memoryMB = memoryMB;
+ this.host = host;
+ }
+
+ /**
+ * @return instance id of the runnable.
+ */
+ @Override
+ public int getInstanceId() {
+ return instanceId;
+ }
+
+ /**
+ * @return id of the container the runnable is running in.
+ */
+ @Override
+ public String getContainerId() {
+ return containerId;
+ }
+
+ /**
+ * @return number of cores the runnable is allowed to use. YARN must be at least v2.1.0 and
+ * it must be configured to use cgroups in order for this to be a reflection of truth.
+ */
+ @Override
+ public int getVirtualCores() {
+ return virtualCores;
+ }
+
+ /**
+ * @return amount of memory in MB the runnable is allowed to use.
+ */
+ @Override
+ public int getMemoryMB() {
+ return memoryMB;
+ }
+
+ /**
+ * @return the host the runnable is running on.
+ */
+ @Override
+ public String getHost() {
+ return host;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof TwillRunResources)) {
+ return false;
+ }
+ TwillRunResources other = (TwillRunResources) o;
+ return (instanceId == other.getInstanceId()) &&
+ containerId.equals(other.getContainerId()) &&
+ host.equals(other.getHost()) &&
+ (virtualCores == other.getVirtualCores()) &&
+ (memoryMB == other.getMemoryMB());
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 17;
+ hash = 31 * hash + containerId.hashCode();
+ hash = 31 * hash + host.hashCode();
+ hash = 31 * hash + (int) (instanceId ^ (instanceId >>> 32));
+ hash = 31 * hash + (int) (virtualCores ^ (virtualCores >>> 32));
+ hash = 31 * hash + (int) (memoryMB ^ (memoryMB >>> 32));
+ return hash;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillRunnableSpecification.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillRunnableSpecification.java b/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillRunnableSpecification.java
new file mode 100644
index 0000000..14ea7f5
--- /dev/null
+++ b/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillRunnableSpecification.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.internal;
+
+import org.apache.twill.api.TwillRunnableSpecification;
+import com.google.common.collect.ImmutableMap;
+
+import java.util.Map;
+
+/**
+ * Straightforward implementation of {@link org.apache.twill.api.TwillRunnableSpecification}.
+ */
+public final class DefaultTwillRunnableSpecification implements TwillRunnableSpecification {
+
+ private final String className;
+ private final String name;
+ private final Map<String, String> arguments;
+
+ public DefaultTwillRunnableSpecification(String className, String name, Map<String, String> arguments) {
+ this.className = className;
+ this.name = name;
+ this.arguments = ImmutableMap.copyOf(arguments);
+ }
+
+ public DefaultTwillRunnableSpecification(String className, TwillRunnableSpecification other) {
+ this.className = className;
+ this.name = other.getName();
+ this.arguments = ImmutableMap.copyOf(other.getConfigs());
+ }
+
+ @Override
+ public String getClassName() {
+ return className;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public Map<String, String> getConfigs() {
+ return arguments;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillSpecification.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillSpecification.java b/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillSpecification.java
new file mode 100644
index 0000000..6bb2b15
--- /dev/null
+++ b/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillSpecification.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.internal;
+
+import org.apache.twill.api.EventHandlerSpecification;
+import org.apache.twill.api.RuntimeSpecification;
+import org.apache.twill.api.TwillSpecification;
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+import javax.annotation.Nullable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Straightforward implementation of {@link org.apache.twill.api.TwillSpecification}.
+ */
+public final class DefaultTwillSpecification implements TwillSpecification {
+
+ private final String name;
+ private final Map<String, RuntimeSpecification> runnables;
+ private final List<Order> orders;
+ private final EventHandlerSpecification eventHandler;
+
+ public DefaultTwillSpecification(String name, Map<String, RuntimeSpecification> runnables,
+ List<Order> orders, EventHandlerSpecification eventHandler) {
+ this.name = name;
+ this.runnables = ImmutableMap.copyOf(runnables);
+ this.orders = ImmutableList.copyOf(orders);
+ this.eventHandler = eventHandler;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public Map<String, RuntimeSpecification> getRunnables() {
+ return runnables;
+ }
+
+ @Override
+ public List<Order> getOrders() {
+ return orders;
+ }
+
+ @Nullable
+ @Override
+ public EventHandlerSpecification getEventHandler() {
+ return eventHandler;
+ }
+
+ /**
+ * Straightforward implementation of {@link Order}.
+ */
+ public static final class DefaultOrder implements Order {
+
+ private final Set<String> names;
+ private final Type type;
+
+ public DefaultOrder(Iterable<String> names, Type type) {
+ this.names = ImmutableSet.copyOf(names);
+ this.type = type;
+ }
+
+ @Override
+ public Set<String> getNames() {
+ return names;
+ }
+
+ @Override
+ public Type getType() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this)
+ .add("names", names)
+ .add("type", type)
+ .toString();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-api/src/main/java/org/apache/twill/internal/RunIds.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/internal/RunIds.java b/twill-api/src/main/java/org/apache/twill/internal/RunIds.java
new file mode 100644
index 0000000..7249d81
--- /dev/null
+++ b/twill-api/src/main/java/org/apache/twill/internal/RunIds.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.internal;
+
+import org.apache.twill.api.RunId;
+import com.google.common.base.Preconditions;
+
+import java.util.UUID;
+
+/**
+ * Factory class for creating instance of {@link org.apache.twill.api.RunId}.
+ */
+public final class RunIds {
+
+ public static RunId generate() {
+ return new RunIdImpl(UUID.randomUUID().toString());
+ }
+
+ public static RunId fromString(String str) {
+ return new RunIdImpl(str);
+ }
+
+ private RunIds() {
+ }
+
+ private static final class RunIdImpl implements RunId {
+
+ final String id;
+
+ private RunIdImpl(String id) {
+ Preconditions.checkArgument(id != null, "RunId cannot be null.");
+ this.id = id;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public String toString() {
+ return getId();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other == null || !(other instanceof RunId)) {
+ return false;
+ }
+ return id.equals(((RunId)other).getId());
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-api/src/main/java/org/apache/twill/internal/package-info.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/internal/package-info.java b/twill-api/src/main/java/org/apache/twill/internal/package-info.java
new file mode 100644
index 0000000..8af8362
--- /dev/null
+++ b/twill-api/src/main/java/org/apache/twill/internal/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Internal classes for Twill API.
+ */
+package org.apache.twill.internal;
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-common/pom.xml
----------------------------------------------------------------------
diff --git a/twill-common/pom.xml b/twill-common/pom.xml
new file mode 100644
index 0000000..a4372f6
--- /dev/null
+++ b/twill-common/pom.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>twill-parent</artifactId>
+ <groupId>org.apache.twill</groupId>
+ <version>0.1.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>twill-common</artifactId>
+ <name>Twill common library</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>jsr305</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-common/src/main/java/org/apache/twill/common/Cancellable.java
----------------------------------------------------------------------
diff --git a/twill-common/src/main/java/org/apache/twill/common/Cancellable.java b/twill-common/src/main/java/org/apache/twill/common/Cancellable.java
new file mode 100644
index 0000000..08f22d3
--- /dev/null
+++ b/twill-common/src/main/java/org/apache/twill/common/Cancellable.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.twill.common;
+
+/**
+ * Something, usually a task, that can be cancelled. Cancellation is performed by the cancel method.
+ */
+public interface Cancellable {
+ /**
+ * Attempts to cancel execution of this task.
+ */
+ void cancel();
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-common/src/main/java/org/apache/twill/common/ServiceListenerAdapter.java
----------------------------------------------------------------------
diff --git a/twill-common/src/main/java/org/apache/twill/common/ServiceListenerAdapter.java b/twill-common/src/main/java/org/apache/twill/common/ServiceListenerAdapter.java
new file mode 100644
index 0000000..527ba7d
--- /dev/null
+++ b/twill-common/src/main/java/org/apache/twill/common/ServiceListenerAdapter.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.common;
+
+import com.google.common.util.concurrent.Service;
+
+/**
+ * An adapter for implementing {@link Service.Listener} with all method default to no-op.
+ */
+public abstract class ServiceListenerAdapter implements Service.Listener {
+ @Override
+ public void starting() {
+ // No-op
+ }
+
+ @Override
+ public void running() {
+ // No-op
+ }
+
+ @Override
+ public void stopping(Service.State from) {
+ // No-op
+ }
+
+ @Override
+ public void terminated(Service.State from) {
+ // No-op
+ }
+
+ @Override
+ public void failed(Service.State from, Throwable failure) {
+ // No-op
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-common/src/main/java/org/apache/twill/common/Services.java
----------------------------------------------------------------------
diff --git a/twill-common/src/main/java/org/apache/twill/common/Services.java b/twill-common/src/main/java/org/apache/twill/common/Services.java
new file mode 100644
index 0000000..7e294f0
--- /dev/null
+++ b/twill-common/src/main/java/org/apache/twill/common/Services.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.common;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.Service;
+import com.google.common.util.concurrent.SettableFuture;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Utility methods for help dealing with {@link Service}.
+ */
+public final class Services {
+
+ /**
+ * Starts a list of {@link Service} one by one. Starting of next Service is triggered from the callback listener
+ * thread of the previous Service.
+ *
+ * @param firstService First service to start.
+ * @param moreServices The rest services to start.
+ * @return A {@link ListenableFuture} that will be completed when all services are started, with the
+ * result carries the completed {@link ListenableFuture} of each corresponding service in the
+ * same order as they are passed to this method.
+ */
+ public static ListenableFuture<List<ListenableFuture<Service.State>>> chainStart(Service firstService,
+ Service...moreServices) {
+ return doChain(true, firstService, moreServices);
+ }
+
+ /**
+ * Stops a list of {@link Service} one by one. It behaves the same as
+ * {@link #chainStart(com.google.common.util.concurrent.Service, com.google.common.util.concurrent.Service...)}
+ * except {@link com.google.common.util.concurrent.Service#stop()} is called instead of start.
+ *
+ * @param firstService First service to stop.
+ * @param moreServices The rest services to stop.
+ * @return A {@link ListenableFuture} that will be completed when all services are stopped.
+ * @see #chainStart(com.google.common.util.concurrent.Service, com.google.common.util.concurrent.Service...)
+ */
+ public static ListenableFuture<List<ListenableFuture<Service.State>>> chainStop(Service firstService,
+ Service...moreServices) {
+ return doChain(false, firstService, moreServices);
+ }
+
+ /**
+ * Returns a {@link ListenableFuture} that will be completed when the given service is stopped. If the service
+ * stopped due to error, the failure cause would be reflected in the future.
+ *
+ * @param service The {@link Service} to block on.
+ * @return A {@link ListenableFuture} that will be completed when the service is stopped.
+ */
+ public static ListenableFuture<Service.State> getCompletionFuture(Service service) {
+ final SettableFuture<Service.State> resultFuture = SettableFuture.create();
+
+ service.addListener(new ServiceListenerAdapter() {
+ @Override
+ public void terminated(Service.State from) {
+ resultFuture.set(Service.State.TERMINATED);
+ }
+
+ @Override
+ public void failed(Service.State from, Throwable failure) {
+ resultFuture.setException(failure);
+ }
+ }, Threads.SAME_THREAD_EXECUTOR);
+
+ Service.State state = service.state();
+ if (state == Service.State.TERMINATED) {
+ return Futures.immediateFuture(state);
+ } else if (state == Service.State.FAILED) {
+ return Futures.immediateFailedFuture(new IllegalStateException("Service failed with unknown exception."));
+ }
+
+ return resultFuture;
+ }
+
+ /**
+ * Performs the actual logic of chain Service start/stop.
+ */
+ private static ListenableFuture<List<ListenableFuture<Service.State>>> doChain(boolean doStart,
+ Service firstService,
+ Service...moreServices) {
+ SettableFuture<List<ListenableFuture<Service.State>>> resultFuture = SettableFuture.create();
+ List<ListenableFuture<Service.State>> result = Lists.newArrayListWithCapacity(moreServices.length + 1);
+
+ ListenableFuture<Service.State> future = doStart ? firstService.start() : firstService.stop();
+ future.addListener(createChainListener(future, moreServices, new AtomicInteger(0), result, resultFuture, doStart),
+ Threads.SAME_THREAD_EXECUTOR);
+ return resultFuture;
+ }
+
+ /**
+ * Returns a {@link Runnable} that can be used as a {@link ListenableFuture} listener to trigger
+ * further service action or completing the result future. Used by
+ * {@link #doChain(boolean, com.google.common.util.concurrent.Service, com.google.common.util.concurrent.Service...)}
+ */
+ private static Runnable createChainListener(final ListenableFuture<Service.State> future, final Service[] services,
+ final AtomicInteger idx,
+ final List<ListenableFuture<Service.State>> result,
+ final SettableFuture<List<ListenableFuture<Service.State>>> resultFuture,
+ final boolean doStart) {
+ return new Runnable() {
+
+ @Override
+ public void run() {
+ result.add(future);
+ int nextIdx = idx.getAndIncrement();
+ if (nextIdx == services.length) {
+ resultFuture.set(result);
+ return;
+ }
+ ListenableFuture<Service.State> actionFuture = doStart ? services[nextIdx].start() : services[nextIdx].stop();
+ actionFuture.addListener(createChainListener(actionFuture, services, idx, result, resultFuture, doStart),
+ Threads.SAME_THREAD_EXECUTOR);
+ }
+ };
+ }
+
+ private Services() {
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-common/src/main/java/org/apache/twill/common/Threads.java
----------------------------------------------------------------------
diff --git a/twill-common/src/main/java/org/apache/twill/common/Threads.java b/twill-common/src/main/java/org/apache/twill/common/Threads.java
new file mode 100644
index 0000000..e33a677
--- /dev/null
+++ b/twill-common/src/main/java/org/apache/twill/common/Threads.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.common;
+
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadFactory;
+
+/**
+ *
+ */
+public final class Threads {
+
+ /**
+ * A executor that execute task from the submitter thread.
+ */
+ public static final Executor SAME_THREAD_EXECUTOR = MoreExecutors.sameThreadExecutor();
+
+ /**
+ * Handy method to create {@link ThreadFactory} that creates daemon threads with the given name format.
+ *
+ * @param nameFormat Name format for the thread names
+ * @return A {@link ThreadFactory}.
+ * @see ThreadFactoryBuilder
+ */
+ public static ThreadFactory createDaemonThreadFactory(String nameFormat) {
+ return new ThreadFactoryBuilder()
+ .setDaemon(true)
+ .setNameFormat(nameFormat)
+ .build();
+ }
+
+ private Threads() {
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-common/src/main/java/org/apache/twill/filesystem/ForwardingLocationFactory.java
----------------------------------------------------------------------
diff --git a/twill-common/src/main/java/org/apache/twill/filesystem/ForwardingLocationFactory.java b/twill-common/src/main/java/org/apache/twill/filesystem/ForwardingLocationFactory.java
new file mode 100644
index 0000000..d25ea20
--- /dev/null
+++ b/twill-common/src/main/java/org/apache/twill/filesystem/ForwardingLocationFactory.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.filesystem;
+
+/**
+ *
+ */
+public abstract class ForwardingLocationFactory implements LocationFactory {
+
+ private final LocationFactory delegate;
+
+ protected ForwardingLocationFactory(LocationFactory delegate) {
+ this.delegate = delegate;
+ }
+
+ public LocationFactory getDelegate() {
+ return delegate;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocation.java
----------------------------------------------------------------------
diff --git a/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocation.java b/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocation.java
new file mode 100644
index 0000000..d107eac
--- /dev/null
+++ b/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocation.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.filesystem;
+
+import com.google.common.collect.Lists;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.UUID;
+
+/**
+ * A concrete implementation of {@link Location} for the Local filesystem.
+ */
+final class LocalLocation implements Location {
+ private final File file;
+
+ /**
+ * Constructs a LocalLocation.
+ *
+ * @param file to the file.
+ */
+ LocalLocation(File file) {
+ this.file = file;
+ }
+
+ /**
+ * Checks if the this location exists on local file system.
+ *
+ * @return true if found; false otherwise.
+ * @throws java.io.IOException
+ */
+ @Override
+ public boolean exists() throws IOException {
+ return file.exists();
+ }
+
+ /**
+ * @return An {@link java.io.InputStream} for this location on local filesystem.
+ * @throws IOException
+ */
+ @Override
+ public InputStream getInputStream() throws IOException {
+ File parent = file.getParentFile();
+ if (!parent.exists()) {
+ parent.mkdirs();
+ }
+ return new FileInputStream(file);
+ }
+
+ /**
+ * @return An {@link java.io.OutputStream} for this location on local filesystem.
+ * @throws IOException
+ */
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ File parent = file.getParentFile();
+ if (!parent.exists()) {
+ parent.mkdirs();
+ }
+ return new FileOutputStream(file);
+ }
+
+ /**
+ * Local location doesn't supports permission. It's the same as calling {@link #getOutputStream()}.
+ */
+ @Override
+ public OutputStream getOutputStream(String permission) throws IOException {
+ return getOutputStream();
+ }
+
+ /**
+ * @return Returns the name of the file or directory denoteed by this abstract pathname.
+ */
+ @Override
+ public String getName() {
+ return file.getName();
+ }
+
+ @Override
+ public boolean createNew() throws IOException {
+ return file.createNewFile();
+ }
+
+ /**
+ * Appends the child to the current {@link Location} on local filesystem.
+ * <p>
+ * Returns a new instance of Location.
+ * </p>
+ *
+ * @param child to be appended to this location.
+ * @return A new instance of {@link Location}
+ * @throws IOException
+ */
+ @Override
+ public Location append(String child) throws IOException {
+ return new LocalLocation(new File(file, child));
+ }
+
+ @Override
+ public Location getTempFile(String suffix) throws IOException {
+ return new LocalLocation(
+ new File(file.getAbsolutePath() + "." + UUID.randomUUID() + (suffix == null ? TEMP_FILE_SUFFIX : suffix)));
+ }
+
+ /**
+ * @return A {@link URI} for this location on local filesystem.
+ */
+ @Override
+ public URI toURI() {
+ return file.toURI();
+ }
+
+ /**
+ * Deletes the file or directory denoted by this abstract pathname. If this
+ * pathname denotes a directory, then the directory must be empty in order
+ * to be deleted.
+ *
+ * @return true if and only if the file or directory is successfully delete; false otherwise.
+ */
+ @Override
+ public boolean delete() throws IOException {
+ return file.delete();
+ }
+
+ @Override
+ public boolean delete(boolean recursive) throws IOException {
+ if (!recursive) {
+ return delete();
+ }
+
+ Deque<File> stack = Lists.newLinkedList();
+ stack.add(file);
+ while (!stack.isEmpty()) {
+ File f = stack.peekLast();
+ File[] files = f.listFiles();
+
+ if (files != null && files.length != 0) {
+ Collections.addAll(stack, files);
+ } else {
+ if (!f.delete()) {
+ return false;
+ }
+ stack.pollLast();
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public Location renameTo(Location destination) throws IOException {
+ // destination will always be of the same type as this location
+ boolean success = file.renameTo(((LocalLocation) destination).file);
+ if (success) {
+ return new LocalLocation(((LocalLocation) destination).file);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Creates the directory named by this abstract pathname, including any necessary
+ * but nonexistent parent directories.
+ *
+ * @return true if and only if the renaming succeeded; false otherwise
+ */
+ @Override
+ public boolean mkdirs() throws IOException {
+ return file.mkdirs();
+ }
+
+ /**
+ * @return Length of file.
+ */
+ @Override
+ public long length() throws IOException {
+ return file.length();
+ }
+
+ @Override
+ public long lastModified() {
+ return file.lastModified();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocationFactory.java
----------------------------------------------------------------------
diff --git a/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocationFactory.java b/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocationFactory.java
new file mode 100644
index 0000000..f44cd87
--- /dev/null
+++ b/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocationFactory.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.filesystem;
+
+import java.io.File;
+import java.net.URI;
+
+/**
+ * A {@link LocationFactory} for creating local file {@link Location}.
+ */
+public final class LocalLocationFactory implements LocationFactory {
+
+ private final File basePath;
+
+ /**
+ * Constructs a LocalLocationFactory that Location created will be relative to system root.
+ */
+ public LocalLocationFactory() {
+ this(new File("/"));
+ }
+
+ public LocalLocationFactory(File basePath) {
+ this.basePath = basePath;
+ }
+
+ @Override
+ public Location create(String path) {
+ return new LocalLocation(new File(basePath, path));
+ }
+
+ @Override
+ public Location create(URI uri) {
+ if (uri.isAbsolute()) {
+ return new LocalLocation(new File(uri));
+ }
+ return new LocalLocation(new File(basePath, uri.getPath()));
+ }
+
+ @Override
+ public Location getHomeLocation() {
+ return new LocalLocation(new File(System.getProperty("user.home")));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-common/src/main/java/org/apache/twill/filesystem/Location.java
----------------------------------------------------------------------
diff --git a/twill-common/src/main/java/org/apache/twill/filesystem/Location.java b/twill-common/src/main/java/org/apache/twill/filesystem/Location.java
new file mode 100644
index 0000000..dee9546
--- /dev/null
+++ b/twill-common/src/main/java/org/apache/twill/filesystem/Location.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.filesystem;
+
+import javax.annotation.Nullable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+
+/**
+ * This interface defines the location and operations of a resource on the filesystem.
+ * <p>
+ * {@link Location} is agnostic to the type of file system the resource is on.
+ * </p>
+ */
+public interface Location {
+ /**
+ * Suffix added to every temp file name generated with {@link #getTempFile(String)}.
+ */
+ static final String TEMP_FILE_SUFFIX = ".tmp";
+
+ /**
+ * Checks if the this location exists.
+ *
+ * @return true if found; false otherwise.
+ * @throws IOException
+ */
+ boolean exists() throws IOException;
+
+ /**
+ * @return Returns the name of the file or directory denoteed by this abstract pathname.
+ */
+ String getName();
+
+ /**
+ * Atomically creates a new, empty file named by this abstract pathname if and only if a file with this name
+ * does not yet exist.
+ * @return {@code true} if the file is successfully create, {@code false} otherwise.
+ * @throws IOException
+ */
+ boolean createNew() throws IOException;
+
+ /**
+ * @return An {@link java.io.InputStream} for this location.
+ * @throws IOException
+ */
+ InputStream getInputStream() throws IOException;
+
+ /**
+ * @return An {@link java.io.OutputStream} for this location.
+ * @throws IOException
+ */
+ OutputStream getOutputStream() throws IOException;
+
+ /**
+ * Creates an {@link OutputStream} for this location with the given permission. The actual permission supported
+ * depends on implementation.
+ *
+ * @param permission A POSIX permission string.
+ * @return An {@link OutputStream} for writing to this location.
+ * @throws IOException If failed to create the {@link OutputStream}.
+ */
+ OutputStream getOutputStream(String permission) throws IOException;
+
+ /**
+ * Appends the child to the current {@link Location}.
+ * <p>
+ * Returns a new instance of Location.
+ * </p>
+ *
+ * @param child to be appended to this location.
+ * @return A new instance of {@link Location}
+ * @throws IOException
+ */
+ Location append(String child) throws IOException;
+
+ /**
+ * Returns unique location for temporary file to be placed near this location.
+ * Allows all temp files to follow same pattern for easier management of them.
+ * @param suffix part of the file name to include in the temp file name
+ * @return location of the temp file
+ * @throws IOException
+ */
+ Location getTempFile(String suffix) throws IOException;
+
+ /**
+ * @return A {@link java.net.URI} for this location.
+ */
+ URI toURI();
+
+ /**
+ * Deletes the file or directory denoted by this abstract pathname. If this
+ * pathname denotes a directory, then the directory must be empty in order
+ * to be deleted.
+ *
+ * @return true if and only if the file or directory is successfully delete; false otherwise.
+ */
+ boolean delete() throws IOException;
+
+ /**
+ * Deletes the file or directory denoted by this abstract pathname. If this
+ * pathname denotes a directory and {@code recursive} is {@code true}, then content of the
+ * directory will be deleted recursively, otherwise the directory must be empty in order to be deleted.
+ * Note that when calling this method with {@code recursive = true} for a directory, any
+ * failure during deletion will have some entries inside the directory being deleted while some are not.
+ *
+ * @param recursive Indicate if recursively delete a directory. Ignored if the pathname represents a file.
+ * @return true if and only if the file or directory is successfully delete; false otherwise.
+ */
+ boolean delete(boolean recursive) throws IOException;
+
+ /**
+ * Moves the file or directory denoted by this abstract pathname.
+ *
+ * @param destination destination location
+ * @return new location if and only if the file or directory is successfully moved; null otherwise.
+ */
+ @Nullable
+ Location renameTo(Location destination) throws IOException;
+
+ /**
+ * Creates the directory named by this abstract pathname, including any necessary
+ * but nonexistent parent directories.
+ *
+ * @return true if and only if the renaming succeeded; false otherwise
+ */
+ boolean mkdirs() throws IOException;
+
+ /**
+ * @return Length of file.
+ */
+ long length() throws IOException;
+
+ /**
+ * @return Last modified time of file.
+ */
+ long lastModified() throws IOException;
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-common/src/main/java/org/apache/twill/filesystem/LocationFactories.java
----------------------------------------------------------------------
diff --git a/twill-common/src/main/java/org/apache/twill/filesystem/LocationFactories.java b/twill-common/src/main/java/org/apache/twill/filesystem/LocationFactories.java
new file mode 100644
index 0000000..751a632
--- /dev/null
+++ b/twill-common/src/main/java/org/apache/twill/filesystem/LocationFactories.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.filesystem;
+
+import com.google.common.base.Throwables;
+
+import java.io.IOException;
+import java.net.URI;
+
+/**
+ * Providers helper methods for creating different {@link LocationFactory}.
+ */
+public final class LocationFactories {
+
+ /**
+ * Creates a {@link LocationFactory} that always applies the giving namespace prefix.
+ */
+ public static LocationFactory namespace(LocationFactory delegate, final String namespace) {
+ return new ForwardingLocationFactory(delegate) {
+ @Override
+ public Location create(String path) {
+ try {
+ Location base = getDelegate().create(namespace);
+ return base.append(path);
+ } catch (IOException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+
+ @Override
+ public Location create(URI uri) {
+ if (uri.isAbsolute()) {
+ return getDelegate().create(uri);
+ }
+ try {
+ Location base = getDelegate().create(namespace);
+ return base.append(uri.getPath());
+ } catch (IOException e) {
+ throw Throwables.propagate(e);
+ }
+ }
+
+ @Override
+ public Location getHomeLocation() {
+ return getDelegate().getHomeLocation();
+ }
+ };
+ }
+
+ private LocationFactories() {
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-common/src/main/java/org/apache/twill/filesystem/LocationFactory.java
----------------------------------------------------------------------
diff --git a/twill-common/src/main/java/org/apache/twill/filesystem/LocationFactory.java b/twill-common/src/main/java/org/apache/twill/filesystem/LocationFactory.java
new file mode 100644
index 0000000..f88d94d
--- /dev/null
+++ b/twill-common/src/main/java/org/apache/twill/filesystem/LocationFactory.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.filesystem;
+
+import java.net.URI;
+
+/**
+ * Factory for creating instance of {@link Location}.
+ */
+public interface LocationFactory {
+
+ /**
+ * Creates an instance of {@link Location} of the given path.
+ * @param path The path representing the location.
+ * @return An instance of {@link Location}.
+ */
+ Location create(String path);
+
+ /**
+ * Creates an instance of {@link Location} based on {@link java.net.URI} <code>uri</code>.
+ *
+ * @param uri to the resource on the filesystem.
+ * @return An instance of {@link Location}
+ */
+ Location create(URI uri);
+
+ /**
+ * Returns the home location.
+ */
+ Location getHomeLocation();
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-common/src/test/java/org/apache/twill/common/ServicesTest.java
----------------------------------------------------------------------
diff --git a/twill-common/src/test/java/org/apache/twill/common/ServicesTest.java b/twill-common/src/test/java/org/apache/twill/common/ServicesTest.java
new file mode 100644
index 0000000..c0aa7ee
--- /dev/null
+++ b/twill-common/src/test/java/org/apache/twill/common/ServicesTest.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.common;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.AbstractIdleService;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.Service;
+import org.junit.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Unit test for {@link Services} methods.
+ */
+public class ServicesTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ServicesTest.class);
+
+ @Test
+ public void testChain() throws ExecutionException, InterruptedException {
+ AtomicBoolean transiting = new AtomicBoolean(false);
+ Service s1 = new DummyService("s1", transiting);
+ Service s2 = new DummyService("s2", transiting);
+ Service s3 = new DummyService("s3", transiting);
+
+ Futures.allAsList(Services.chainStart(s1, s2, s3).get()).get();
+ Futures.allAsList(Services.chainStop(s3, s2, s1).get()).get();
+ }
+
+ @Test
+ public void testCompletion() throws ExecutionException, InterruptedException {
+ Service service = new DummyService("s1", new AtomicBoolean());
+ ListenableFuture<Service.State> completion = Services.getCompletionFuture(service);
+
+ service.start();
+ service.stop();
+
+ completion.get();
+
+ AtomicBoolean transiting = new AtomicBoolean();
+ service = new DummyService("s2", transiting);
+ completion = Services.getCompletionFuture(service);
+
+ service.startAndWait();
+ transiting.set(true);
+ service.stop();
+
+ try {
+ completion.get();
+ Assert.assertTrue(false);
+ } catch (ExecutionException e) {
+ // Expected
+ }
+ }
+
+ private static final class DummyService extends AbstractIdleService {
+
+ private final String name;
+ private final AtomicBoolean transiting;
+
+ private DummyService(String name, AtomicBoolean transiting) {
+ this.name = name;
+ this.transiting = transiting;
+ }
+
+ @Override
+ protected void startUp() throws Exception {
+ Preconditions.checkState(transiting.compareAndSet(false, true));
+ LOG.info("Starting: " + name);
+ TimeUnit.MILLISECONDS.sleep(500);
+ LOG.info("Started: " + name);
+ Preconditions.checkState(transiting.compareAndSet(true, false));
+ }
+
+ @Override
+ protected void shutDown() throws Exception {
+ Preconditions.checkState(transiting.compareAndSet(false, true));
+ LOG.info("Stopping: " + name);
+ TimeUnit.MILLISECONDS.sleep(500);
+ LOG.info("Stopped: " + name);
+ Preconditions.checkState(transiting.compareAndSet(true, false));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-common/src/test/java/org/apache/twill/filesystem/LocalLocationTest.java
----------------------------------------------------------------------
diff --git a/twill-common/src/test/java/org/apache/twill/filesystem/LocalLocationTest.java b/twill-common/src/test/java/org/apache/twill/filesystem/LocalLocationTest.java
new file mode 100644
index 0000000..198f77f
--- /dev/null
+++ b/twill-common/src/test/java/org/apache/twill/filesystem/LocalLocationTest.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.twill.filesystem;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+
+/**
+ *
+ */
+public class LocalLocationTest {
+
+ @Test
+ public void testDelete() throws IOException {
+ LocationFactory factory = new LocalLocationFactory(new File(System.getProperty("java.io.tmpdir")));
+
+ Location base = factory.create("test").getTempFile(".tmp");
+ Assert.assertTrue(base.mkdirs());
+
+ Assert.assertTrue(base.append("test1").getTempFile(".tmp").createNew());
+ Assert.assertTrue(base.append("test2").getTempFile(".tmp").createNew());
+
+ Location subDir = base.append("test3");
+ Assert.assertTrue(subDir.mkdirs());
+
+ Assert.assertTrue(subDir.append("test4").getTempFile(".tmp").createNew());
+ Assert.assertTrue(subDir.append("test5").getTempFile(".tmp").createNew());
+
+ Assert.assertTrue(base.delete(true));
+ Assert.assertFalse(base.exists());
+ }
+
+ @Test
+ public void testHelper() {
+ LocationFactory factory = LocationFactories.namespace(
+ new LocalLocationFactory(new File(System.getProperty("java.io.tmpdir"))),
+ "testhelper");
+
+ Location location = factory.create("test");
+ Assert.assertTrue(location.toURI().getPath().endsWith("testhelper/test"));
+
+ location = factory.create(URI.create("test2"));
+ Assert.assertTrue(location.toURI().getPath().endsWith("testhelper/test2"));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/35dfccc4/twill-core/pom.xml
----------------------------------------------------------------------
diff --git a/twill-core/pom.xml b/twill-core/pom.xml
new file mode 100644
index 0000000..faff711
--- /dev/null
+++ b/twill-core/pom.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>twill-parent</artifactId>
+ <groupId>org.apache.twill</groupId>
+ <version>0.1.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>twill-core</artifactId>
+ <name>Twill core library</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>twill-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>twill-zookeeper</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>twill-discovery-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.xerial.snappy</groupId>
+ <artifactId>snappy-java</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-all</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-compress</artifactId>
+ </dependency>
+ </dependencies>
+</project>