summaryrefslogtreecommitdiffstats
path: root/sched
diff options
context:
space:
mode:
Diffstat (limited to 'sched')
-rw-r--r--sched/.settings/findbugs-exclude.xml5
-rw-r--r--sched/.settings/org.eclipse.jdt.core.prefs2
-rw-r--r--sched/src/com/android/sched/SchedProperties.java5
-rw-r--r--sched/src/com/android/sched/scheduler/MultiWorkersScheduleInstance.java2
-rw-r--r--sched/src/com/android/sched/scheduler/genetic/GeneticEventType.java20
-rw-r--r--sched/src/com/android/sched/util/Colors.java94
-rw-r--r--sched/src/com/android/sched/util/ConcurrentIOException.java32
-rw-r--r--sched/src/com/android/sched/util/UnrecoverableException.java38
-rw-r--r--sched/src/com/android/sched/util/codec/ClassSelector.java6
-rw-r--r--sched/src/com/android/sched/util/codec/DefaultFactorySelector.java7
-rw-r--r--sched/src/com/android/sched/util/codec/DoubleCodec.java2
-rw-r--r--sched/src/com/android/sched/util/codec/ImplementationSelector.java7
-rw-r--r--sched/src/com/android/sched/util/codec/KeyValueCodec.java26
-rw-r--r--sched/src/com/android/sched/util/codec/LongCodec.java2
-rw-r--r--sched/src/com/android/sched/util/codec/ReflectFactorySelector.java7
-rw-r--r--sched/src/com/android/sched/util/codec/Selector.java13
-rw-r--r--sched/src/com/android/sched/util/config/AsapConfigBuilder.java327
-rw-r--r--sched/src/com/android/sched/util/config/Config.java8
-rw-r--r--sched/src/com/android/sched/util/config/ConfigChecker.java93
-rw-r--r--sched/src/com/android/sched/util/config/ConfigDebug.java20
-rw-r--r--sched/src/com/android/sched/util/config/ConfigImpl.java130
-rw-r--r--sched/src/com/android/sched/util/config/ConfigurationError.java5
-rw-r--r--sched/src/com/android/sched/util/config/GatherConfigBuilder.java200
-rw-r--r--sched/src/com/android/sched/util/config/InternalConfig.java31
-rw-r--r--sched/src/com/android/sched/util/config/ThreadConfig.java37
-rw-r--r--sched/src/com/android/sched/util/config/UninitializedConfig.java21
-rw-r--r--sched/src/com/android/sched/util/config/VariableDoesNotMatchConfigurationException.java2
-rw-r--r--sched/src/com/android/sched/util/config/VariableMatchesSeveralConfigurationException.java2
-rw-r--r--sched/src/com/android/sched/util/config/ZipLocation.java18
-rw-r--r--sched/src/com/android/sched/util/config/id/BooleanPropertyId.java15
-rw-r--r--sched/src/com/android/sched/util/config/id/DoublePropertyId.java15
-rw-r--r--sched/src/com/android/sched/util/config/id/EnumPropertyId.java8
-rw-r--r--sched/src/com/android/sched/util/config/id/IntegerPropertyId.java14
-rw-r--r--sched/src/com/android/sched/util/config/id/KeyId.java22
-rw-r--r--sched/src/com/android/sched/util/config/id/ListPropertyId.java9
-rw-r--r--sched/src/com/android/sched/util/config/id/LongPropertyId.java15
-rw-r--r--sched/src/com/android/sched/util/config/id/ProbabilityPropertyId.java18
-rw-r--r--sched/src/com/android/sched/util/config/id/PropertyId.java190
-rw-r--r--sched/src/com/android/sched/util/log/EventType.java1
-rw-r--r--sched/src/com/android/sched/util/log/SchedEventType.java17
-rw-r--r--sched/src/com/android/sched/util/log/StatisticOnlyTracer.java118
-rw-r--r--sched/src/com/android/sched/util/log/stats/Alloc.java43
-rw-r--r--sched/src/com/android/sched/util/log/stats/AllocImpl.java29
-rw-r--r--sched/src/com/android/sched/util/log/stats/ArrayAlloc.java60
-rw-r--r--sched/src/com/android/sched/util/log/stats/ArrayAllocImpl.java29
-rw-r--r--sched/src/com/android/sched/util/log/stats/Counter.java41
-rw-r--r--sched/src/com/android/sched/util/log/stats/CounterImpl.java19
-rw-r--r--sched/src/com/android/sched/util/log/stats/ExtendedSample.java131
-rw-r--r--sched/src/com/android/sched/util/log/stats/ExtendedSampleImpl.java187
-rw-r--r--sched/src/com/android/sched/util/log/stats/ObjectAlloc.java46
-rw-r--r--sched/src/com/android/sched/util/log/stats/ObjectAllocImpl.java33
-rw-r--r--sched/src/com/android/sched/util/log/stats/Percent.java49
-rw-r--r--sched/src/com/android/sched/util/log/stats/PercentImpl.java70
-rw-r--r--sched/src/com/android/sched/util/log/stats/Sample.java82
-rw-r--r--sched/src/com/android/sched/util/log/stats/SampleImpl.java139
-rw-r--r--sched/src/com/android/sched/util/log/stats/Statistic.java48
-rw-r--r--sched/src/com/android/sched/util/log/stats/StatisticId.java15
-rw-r--r--sched/src/com/android/sched/util/log/tracer/DynamicEventType.java10
-rw-r--r--sched/src/com/android/sched/util/log/tracer/TracerEventType.java18
-rw-r--r--sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java59
-rw-r--r--sched/src/com/android/sched/util/log/tracer/watcher/DetailedAllocationWatcher.java132
-rw-r--r--sched/src/com/android/sched/vfs/AbstractVElement.java31
-rw-r--r--sched/src/com/android/sched/vfs/InputVDir.java31
-rw-r--r--sched/src/com/android/sched/vfs/InputVFile.java32
-rw-r--r--sched/src/com/android/sched/vfs/OutputVDir.java31
-rw-r--r--sched/src/com/android/sched/vfs/OutputVFile.java32
-rw-r--r--sched/src/com/android/sched/vfs/VElement.java34
-rw-r--r--sched/src/com/android/sched/vfs/direct/InputDirectDir.java93
-rw-r--r--sched/src/com/android/sched/vfs/direct/InputDirectFile.java64
-rw-r--r--sched/src/com/android/sched/vfs/direct/ListDirException.java41
-rw-r--r--sched/src/com/android/sched/vfs/direct/OutputDirectDir.java67
-rw-r--r--sched/src/com/android/sched/vfs/direct/OutputDirectFile.java66
-rw-r--r--sched/src/com/android/sched/vfs/zip/InputZipArchive.java72
-rw-r--r--sched/src/com/android/sched/vfs/zip/InputZipVDir.java66
-rw-r--r--sched/src/com/android/sched/vfs/zip/InputZipVFile.java66
-rw-r--r--sched/src/com/android/sched/vfs/zip/OutputZipRootVDir.java80
-rw-r--r--sched/src/com/android/sched/vfs/zip/OutputZipVFile.java68
77 files changed, 2712 insertions, 1006 deletions
diff --git a/sched/.settings/findbugs-exclude.xml b/sched/.settings/findbugs-exclude.xml
index 404658b..e21c2b2 100644
--- a/sched/.settings/findbugs-exclude.xml
+++ b/sched/.settings/findbugs-exclude.xml
@@ -23,6 +23,11 @@
</Match>
<!-- See inlined comment in source file -->
<Match>
+ <Class name="com.android.sched.util.log.stats.SampleImpl"/>
+ <Bug pattern="IS2_INCONSISTENT_SYNC"/>
+</Match>
+<!-- See inlined comment in source file -->
+<Match>
<Class name="com.android.sched.util.table.AbstractTable"/>
<Bug pattern="EI_EXPOSE_REP"/>
</Match>
diff --git a/sched/.settings/org.eclipse.jdt.core.prefs b/sched/.settings/org.eclipse.jdt.core.prefs
index 82380d3..34af015 100644
--- a/sched/.settings/org.eclipse.jdt.core.prefs
+++ b/sched/.settings/org.eclipse.jdt.core.prefs
@@ -188,7 +188,7 @@ org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
-org.eclipse.jdt.core.formatter.comment.format_header=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
org.eclipse.jdt.core.formatter.comment.format_html=true
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
diff --git a/sched/src/com/android/sched/SchedProperties.java b/sched/src/com/android/sched/SchedProperties.java
index c9edf55..5594905 100644
--- a/sched/src/com/android/sched/SchedProperties.java
+++ b/sched/src/com/android/sched/SchedProperties.java
@@ -16,6 +16,7 @@
package com.android.sched;
+import com.android.sched.item.onlyfor.Default;
import com.android.sched.item.onlyfor.OnlyForType;
import com.android.sched.util.codec.ClassSelector;
import com.android.sched.util.config.HasKeyId;
@@ -32,10 +33,10 @@ public class SchedProperties {
@Nonnull
public static final BooleanPropertyId FAILED_STOP = BooleanPropertyId.create(
"sched.failedstop", "Define if the SchedLib stop at the first failed")
- .addDefaultValue("true");
+ .addDefaultValue(Boolean.TRUE);
@Nonnull
public static final PropertyId<Class<? extends OnlyForType>> ONLY_FOR = PropertyId.create(
"sched.onlyfor", "Define which items to take into account",
- new ClassSelector<OnlyForType>(OnlyForType.class)).addDefaultValue("default");
+ new ClassSelector<OnlyForType>(OnlyForType.class)).addDefaultValue(Default.class);
}
diff --git a/sched/src/com/android/sched/scheduler/MultiWorkersScheduleInstance.java b/sched/src/com/android/sched/scheduler/MultiWorkersScheduleInstance.java
index de04742..64da80f 100644
--- a/sched/src/com/android/sched/scheduler/MultiWorkersScheduleInstance.java
+++ b/sched/src/com/android/sched/scheduler/MultiWorkersScheduleInstance.java
@@ -65,7 +65,7 @@ public class MultiWorkersScheduleInstance<T extends Component>
"sched.runner.thread.synchronized",
"If scheduler manages synchronized schedulable by itself").requiredIf(
ScheduleInstance.DEFAULT_RUNNER.getClazz().isSubClassOf(MultiWorkersScheduleInstance.class))
- .addDefaultValue("true");
+ .addDefaultValue(Boolean.TRUE);
@Nonnull
private static final IntegerPropertyId CHECK_FREQUENCY = IntegerPropertyId.create(
diff --git a/sched/src/com/android/sched/scheduler/genetic/GeneticEventType.java b/sched/src/com/android/sched/scheduler/genetic/GeneticEventType.java
index 049b935..a8777d5 100644
--- a/sched/src/com/android/sched/scheduler/genetic/GeneticEventType.java
+++ b/sched/src/com/android/sched/scheduler/genetic/GeneticEventType.java
@@ -25,24 +25,16 @@ import javax.annotation.Nonnull;
* Represents a type of event whose performance is tracked
*/
enum GeneticEventType implements EventType {
- ENGINE("Genetic engine", "Red"),
- ANALYZER("Genetic analizing plan", "Red"),
- BUILDER("Genetic builder builder", "Red"),
- RANDOM_INIT("Random generator initializer", "Red");
- @Nonnull
- private final String cssColor;
+ ENGINE("Genetic engine"),
+ ANALYZER("Genetic analizing plan"),
+ BUILDER("Genetic builder builder"),
+ RANDOM_INIT("Random generator initializer");
+
@Nonnull
private final String name;
- GeneticEventType(@Nonnull String name, @Nonnull String cssColor) {
+ GeneticEventType(@Nonnull String name) {
this.name = name;
- this.cssColor = cssColor;
- }
-
- @Override
- @Nonnull
- public String getColor() {
- return cssColor;
}
@Override
diff --git a/sched/src/com/android/sched/util/Colors.java b/sched/src/com/android/sched/util/Colors.java
deleted file mode 100644
index 69c8372..0000000
--- a/sched/src/com/android/sched/util/Colors.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed 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 com.android.sched.util;
-
-import java.awt.Color;
-import java.util.Random;
-
-import javax.annotation.Nonnull;
-
-/**
- * Utility class to manipulate Color.
- */
-public class Colors {
- /**
- * Return a valid string describing a color valid for Css.
- * @param color the color
- * @return the string describing the color
- */
- @Nonnull
- public static String getCssColor(@Nonnull Color color) {
- StringBuffer buffer = new StringBuffer(7);
- buffer.append('#');
- buffer.append(getHexColorComponent(color.getRed()));
- buffer.append(getHexColorComponent(color.getGreen()));
- buffer.append(getHexColorComponent(color.getBlue()));
-
- return buffer.toString();
- }
-
- @Nonnull
- private static String getHexColorComponent(int colorComponent) {
- String hex = Integer.toString(colorComponent, 16);
-
- // Make sure hex value is two digits
- if (hex.length() == 1) {
- hex = "0" + hex;
- }
-
- return hex;
- }
-
- /**
- * Create a random pastel color.
- *
- * @return a color
- */
- @Nonnull
- public static Color getRandomPastel() {
- Random random = new Random();
-
- final float hue = random.nextFloat();
- final float saturation = 0.9f; // 1.0 for brilliant, 0.0 for dull
- final float luminance = 1.0f; // 1.0 for brighter, 0.0 for black
-
- return Color.getHSBColor(hue, saturation, luminance);
- }
-
- /**
- * Create a random pastel color based on a seed.
- *
- * @param seed the seed
- * @return a color
- */
- @Nonnull
- public static Color getRandomPastel(int seed) {
- final float hue;
- if (seed != 0) {
- hue = 1.0F / ((((long) seed) << 32) >>> 32); // Remove the sign
- } else {
- hue = 1.0F;
- }
-
- final float saturation = 0.9f; // 1.0 for brilliant, 0.0 for dull
- final float luminance = 1.0f; // 1.0 for brighter, 0.0 for black
-
- return Color.getHSBColor(hue, saturation, luminance);
- }
-
- private Colors() {}
-}
diff --git a/sched/src/com/android/sched/util/ConcurrentIOException.java b/sched/src/com/android/sched/util/ConcurrentIOException.java
new file mode 100644
index 0000000..b3ea109
--- /dev/null
+++ b/sched/src/com/android/sched/util/ConcurrentIOException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.util;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Thrown when an external change to the file system prevents continuing the current processing.
+ */
+public class ConcurrentIOException extends UnrecoverableException {
+
+ private static final long serialVersionUID = 1L;
+
+ public ConcurrentIOException(@Nonnull Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/sched/src/com/android/sched/util/UnrecoverableException.java b/sched/src/com/android/sched/util/UnrecoverableException.java
new file mode 100644
index 0000000..a3f2dff
--- /dev/null
+++ b/sched/src/com/android/sched/util/UnrecoverableException.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.util;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Thrown when a major problem occurred because of an event out of our control.
+ * Handling this error should only be reporting to the user and maybe just retry exactly the same
+ * thing as the one that has thrown.
+ */
+public abstract class UnrecoverableException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ public UnrecoverableException(@Nonnull Throwable cause) {
+ super(cause);
+ }
+
+ @Override
+ public String getMessage() {
+ return getCause().getMessage();
+ }
+}
diff --git a/sched/src/com/android/sched/util/codec/ClassSelector.java b/sched/src/com/android/sched/util/codec/ClassSelector.java
index c8f45c5..f3f8cb9 100644
--- a/sched/src/com/android/sched/util/codec/ClassSelector.java
+++ b/sched/src/com/android/sched/util/codec/ClassSelector.java
@@ -18,6 +18,8 @@ package com.android.sched.util.codec;
+import com.google.common.base.Joiner;
+
import com.android.sched.util.config.ConfigurationError;
import javax.annotation.Nonnull;
@@ -44,8 +46,8 @@ public class ClassSelector<T> extends Selector<T> implements StringCodec<Class<?
public void checkValue(@Nonnull CodecContext context, @Nonnull Class<? extends T> cls)
throws CheckingException {
if (!checkClass(cls)) {
- throw new CheckingException(
- "The value must be " + getUsage() + " but is '" + formatValue(cls) + "'");
+ throw new CheckingException("The value must be {" + Joiner.on(',').join(getClasses())
+ + "} but is '" + cls.getCanonicalName() + "'");
}
}
diff --git a/sched/src/com/android/sched/util/codec/DefaultFactorySelector.java b/sched/src/com/android/sched/util/codec/DefaultFactorySelector.java
index c357b9d..6a5c110 100644
--- a/sched/src/com/android/sched/util/codec/DefaultFactorySelector.java
+++ b/sched/src/com/android/sched/util/codec/DefaultFactorySelector.java
@@ -17,6 +17,8 @@
package com.android.sched.util.codec;
+import com.google.common.base.Joiner;
+
import com.android.sched.util.config.ConfigurationError;
import com.android.sched.util.config.DefaultFactory;
import com.android.sched.util.config.ReflectDefaultCtorFactory;
@@ -56,8 +58,9 @@ public class DefaultFactorySelector<T> extends Selector<T>
public void checkValue(@Nonnull CodecContext context, @Nonnull DefaultFactory<T> factory)
throws CheckingException {
if (!checkClass(factory.getInstanciatedClass())) {
- throw new CheckingException(
- "The value must be " + getUsage() + " but is '" + formatValue(factory) + "'");
+ throw new CheckingException("The value must be a DefaultFactory<{"
+ + Joiner.on(',').join(getClasses()) + "}> but is a DefaultFactory<"
+ + factory.getInstanciatedClass().getCanonicalName() + ">");
}
}
diff --git a/sched/src/com/android/sched/util/codec/DoubleCodec.java b/sched/src/com/android/sched/util/codec/DoubleCodec.java
index 44ee717..a2be42f 100644
--- a/sched/src/com/android/sched/util/codec/DoubleCodec.java
+++ b/sched/src/com/android/sched/util/codec/DoubleCodec.java
@@ -72,7 +72,7 @@ public class DoubleCodec implements StringCodec<Double> {
if (v < min || v > max) {
throw new CheckingException(
- "The value must be " + getUsage() + " but is '" + formatValue(d) + "'");
+ "The value must be " + getUsage() + " but is " + d);
}
}
diff --git a/sched/src/com/android/sched/util/codec/ImplementationSelector.java b/sched/src/com/android/sched/util/codec/ImplementationSelector.java
index 1f06a15..e242be7 100644
--- a/sched/src/com/android/sched/util/codec/ImplementationSelector.java
+++ b/sched/src/com/android/sched/util/codec/ImplementationSelector.java
@@ -16,6 +16,8 @@
package com.android.sched.util.codec;
+import com.google.common.base.Joiner;
+
import com.android.sched.util.config.ConfigurationError;
import com.android.sched.util.config.ReflectDefaultCtorFactory;
@@ -56,8 +58,9 @@ public class ImplementationSelector<T> extends Selector<T> implements StringCode
public void checkValue(@Nonnull CodecContext context, @Nonnull T data)
throws CheckingException {
if (!checkClass((Class<? extends T>) data.getClass())) {
- throw new CheckingException(
- "The value must be " + getUsage() + " but is '" + formatValue(data) + "'");
+ throw new CheckingException("The value must be an instance of {"
+ + Joiner.on(',').join(getClasses()) + "} but is an instance of '"
+ + data.getClass().getCanonicalName() + "'");
}
}
diff --git a/sched/src/com/android/sched/util/codec/KeyValueCodec.java b/sched/src/com/android/sched/util/codec/KeyValueCodec.java
index ec9db66..4f16b47 100644
--- a/sched/src/com/android/sched/util/codec/KeyValueCodec.java
+++ b/sched/src/com/android/sched/util/codec/KeyValueCodec.java
@@ -20,6 +20,8 @@ import com.android.sched.util.config.ConfigurationError;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
import javax.annotation.Nonnull;
@@ -109,8 +111,28 @@ public class KeyValueCodec<T> implements StringCodec<T> {
}
}
- throw new CheckingException(
- "The value must be " + getUsage() + " but is '" + formatValue(value) + "'");
+ Set<T> set = new HashSet<T>();
+ for (Entry<T> entry : entries) {
+ set.add(entry.value);
+ }
+
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for (T data : set) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(", ");
+ }
+
+ sb.append(data);
+ sb.append(" (");
+ sb.append(data.getClass().getCanonicalName());
+ sb.append(')');
+ }
+
+ throw new CheckingException("The value must be {" + sb.toString() + "} but is '" + value + " ("
+ + value.getClass().getCanonicalName() + ")'");
}
@Override
diff --git a/sched/src/com/android/sched/util/codec/LongCodec.java b/sched/src/com/android/sched/util/codec/LongCodec.java
index 4c4153c..cf9b8da 100644
--- a/sched/src/com/android/sched/util/codec/LongCodec.java
+++ b/sched/src/com/android/sched/util/codec/LongCodec.java
@@ -76,7 +76,7 @@ public class LongCodec implements StringCodec<Long>{
if (v < min || v > max) {
throw new CheckingException(
- "The value must be " + getUsage() + " but is '" + formatValue(l) + "'");
+ "The value must be " + getUsage() + " but is " + l);
}
}
diff --git a/sched/src/com/android/sched/util/codec/ReflectFactorySelector.java b/sched/src/com/android/sched/util/codec/ReflectFactorySelector.java
index 43819f7..3ea1073 100644
--- a/sched/src/com/android/sched/util/codec/ReflectFactorySelector.java
+++ b/sched/src/com/android/sched/util/codec/ReflectFactorySelector.java
@@ -16,6 +16,8 @@
package com.android.sched.util.codec;
+import com.google.common.base.Joiner;
+
import com.android.sched.util.config.ConfigurationError;
import com.android.sched.util.config.ReflectFactory;
@@ -78,8 +80,9 @@ public class ReflectFactorySelector<T>
public void checkValue(@Nonnull CodecContext context, @Nonnull ReflectFactory<T> factory)
throws CheckingException {
if (!checkClass(factory.getInstanciatedClass())) {
- throw new CheckingException(
- "The value must be " + getUsage() + " but is '" + formatValue(factory) + "'");
+ throw new CheckingException("The value must be a ReflectFactory<{"
+ + Joiner.on(',').join(getClasses()) + "}> but is a ReflectFactory<"
+ + factory.getInstanciatedClass().getCanonicalName() + ">");
}
}
diff --git a/sched/src/com/android/sched/util/codec/Selector.java b/sched/src/com/android/sched/util/codec/Selector.java
index 799f106..3e4d90e 100644
--- a/sched/src/com/android/sched/util/codec/Selector.java
+++ b/sched/src/com/android/sched/util/codec/Selector.java
@@ -27,6 +27,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -85,6 +86,7 @@ public abstract class Selector<T> {
public String getName(@Nonnull Class<? extends T> type) {
ensureScan();
assert propertyValues != null;
+
for (Entry<String, Class<? extends T>> entry : propertyValues.entrySet()) {
if (entry.getValue() == type) {
return entry.getKey();
@@ -127,6 +129,17 @@ public abstract class Selector<T> {
return list;
}
+ @Nonnull
+ public Set<Class<? extends T>> getClasses() {
+ ensureScan();
+ assert propertyValues != null;
+
+ Set<Class<? extends T>> set = new HashSet<Class<? extends T>>();
+ set.addAll(propertyValues.values());
+
+ return set;
+ }
+
private synchronized void ensureScan() {
if (propertyValues == null) {
propertyValues = new HashMap<String, Class<? extends T>>();
diff --git a/sched/src/com/android/sched/util/config/AsapConfigBuilder.java b/sched/src/com/android/sched/util/config/AsapConfigBuilder.java
index 0b8bdf2..597d44e 100644
--- a/sched/src/com/android/sched/util/config/AsapConfigBuilder.java
+++ b/sched/src/com/android/sched/util/config/AsapConfigBuilder.java
@@ -38,6 +38,7 @@ import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -69,11 +70,11 @@ public class AsapConfigBuilder {
new HashMap<KeyId<?, ?>, FieldLocation>();
@Nonnull
- private final Map<PropertyId<?>, String> stringValuesById =
- new HashMap<PropertyId<?>, String>();
+ private final Map<PropertyId<?>, PropertyId<?>.Value> valuesById =
+ new HashMap<PropertyId<?>, PropertyId<?>.Value>();
@Nonnull
- private final Map<ObjectId<?>, Object> instanceValuesById =
+ private final Map<ObjectId<?>, Object> instances =
new HashMap<ObjectId<?>, Object>();
@Nonnull
@@ -182,13 +183,7 @@ public class AsapConfigBuilder {
}
@Nonnull
- public AsapConfigBuilder set(@Nonnull String name, @Nonnull String value)
- throws UnknownPropertyNameException, PropertyIdException {
- return set(name, value, defaultLocations.peek());
- }
-
- @Nonnull
- public AsapConfigBuilder set(
+ public AsapConfigBuilder setString(
@Nonnull String name, @Nonnull String value, @Nonnull Location location)
throws UnknownPropertyNameException, PropertyIdException {
KeyId<?, ?> keyId = keyIdsByName.get(name);
@@ -197,7 +192,7 @@ public class AsapConfigBuilder {
}
try {
- set((PropertyId<?>) keyId, value, location);
+ setString((PropertyId<?>) keyId, value, location);
} catch (UnknownPropertyIdException e) {
throw new AssertionError();
}
@@ -206,13 +201,36 @@ public class AsapConfigBuilder {
}
@Nonnull
- public AsapConfigBuilder set(@Nonnull PropertyId<?> propertyId, @Nonnull String value)
- throws PropertyIdException {
- return set(propertyId, value, defaultLocations.peek());
+ public <T> AsapConfigBuilder set(
+ @Nonnull String name, @Nonnull T value, @Nonnull Location location)
+ throws UnknownPropertyNameException, PropertyIdException {
+ KeyId<?, ?> keyId = keyIdsByName.get(name);
+ if (keyId == null || !(keyId instanceof PropertyId)) {
+ throw new UnknownPropertyNameException(name);
+ }
+
+ @SuppressWarnings("unchecked")
+ PropertyId<T> propertyId = (PropertyId<T>) keyId;
+
+ if (context.isDebug()) {
+ try {
+ propertyId.getCodec().checkValue(context, value);
+ } catch (Exception e) {
+ throw new ConfigurationError("Property '" + name + "': " + e.getMessage());
+ }
+ }
+
+ try {
+ set(propertyId, value, location);
+ } catch (UnknownPropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
}
@Nonnull
- public AsapConfigBuilder set(
+ public AsapConfigBuilder setString(
@Nonnull PropertyId<?> propertyId, @Nonnull String value, @Nonnull Location location)
throws PropertyIdException {
if (!keyIdsByName.values().contains(propertyId)) {
@@ -227,21 +245,39 @@ public class AsapConfigBuilder {
}
}
- stringValuesById.put(propertyId, value);
+ valuesById.put(propertyId, propertyId.new Value(value));
locationsByKeyId.put(propertyId, location);
return this;
}
+
@Nonnull
- public <T> AsapConfigBuilder set(@Nonnull ObjectId<T> objectId, @Nonnull T value) {
- return set(objectId, value, defaultLocations.peek());
+ public <T> AsapConfigBuilder set(
+ @Nonnull PropertyId<T> propertyId, @Nonnull T value, @Nonnull Location location)
+ throws PropertyIdException {
+ if (!keyIdsByName.values().contains(propertyId)) {
+ throw new UnknownPropertyIdException(propertyId);
+ }
+
+ if (context.isDebug()) {
+ try {
+ propertyId.getCodec().checkValue(context, value);
+ } catch (Exception e) {
+ throw new ConfigurationError("Property '" + propertyId.getName() + "': " + e.getMessage());
+ }
+ }
+
+ valuesById.put(propertyId, propertyId.new Value(value));
+ locationsByKeyId.put(propertyId, location);
+
+ return this;
}
@Nonnull
public <T> AsapConfigBuilder set(
@Nonnull ObjectId<T> objectId, @Nonnull T value, @Nonnull Location location) {
- instanceValuesById.put(objectId, value);
+ instances.put(objectId, value);
locationsByKeyId.put(objectId, location);
return this;
@@ -276,7 +312,7 @@ public class AsapConfigBuilder {
* @throws ConfigurationException
*/
@Nonnull
- public Config build() throws ConfigurationException {
+ public <X> Config build() throws ConfigurationException {
ChainedExceptionBuilder<ConfigurationException> exceptions =
new ChainedExceptionBuilder<ConfigurationException>();
@@ -286,12 +322,14 @@ public class AsapConfigBuilder {
logger.setLevel(Level.INFO);
}
- @Nonnull Map<PropertyId<?>, String> values = new HashMap<PropertyId<?>, String>();
+ @Nonnull
+ Map<PropertyId<?>, PropertyId<?>.Value> values =
+ new HashMap<PropertyId<?>, PropertyId<?>.Value>();
processValues(values);
processDefaultValues(values);
ConfigChecker checker =
- new ConfigChecker(context, values, instanceValuesById, locationsByKeyId);
+ new ConfigChecker(context, values, instances, locationsByKeyId);
for (KeyId<?, ?> keyId : keyIdsByName.values()) {
boolean needChecks = false;
@@ -343,15 +381,15 @@ public class AsapConfigBuilder {
if (context.isDebug()) {
return new ConfigDebug(
- context, checker.getStrings(), checker.getInstances(), checker.getDropCauses());
+ context, checker.getValues(), checker.getInstances(), checker.getDropCauses());
} else {
- return new ConfigImpl(context, checker.getStrings(), checker.getInstances());
+ return new ConfigImpl(context, checker.getValues(), checker.getInstances());
}
}
@Nonnull
public Collection<PropertyId<?>> getPropertyIds() {
- ArrayList<PropertyId<?>> result = new ArrayList<PropertyId<?>>(keyIdsByName.size());
+ List<PropertyId<?>> result = new ArrayList<PropertyId<?>>(keyIdsByName.size());
for (KeyId<?, ?> keyId : keyIdsByName.values()) {
if (keyId.isPublic() && keyId instanceof PropertyId<?>) {
@@ -363,15 +401,21 @@ public class AsapConfigBuilder {
}
@CheckForNull
- public String getDefaultValue(@Nonnull PropertyId<?> propertyId) {
- return propertyId.getDefaultValue(context);
+ public <T> String getDefaultValue(@Nonnull PropertyId<T> propertyId) {
+ PropertyId<T>.Value value = propertyId.getDefaultValue(context);
+
+ if (value != null) {
+ return value.getString();
+ } else {
+ return null;
+ }
}
- private void processValues(@Nonnull Map<PropertyId<?>, String> values) {
- values.putAll(stringValuesById);
+ private void processValues(@Nonnull Map<PropertyId<?>, PropertyId<?>.Value> values) {
+ values.putAll(valuesById);
}
- private void processDefaultValues(@Nonnull Map<PropertyId<?>, String> values) {
+ private void processDefaultValues(@Nonnull Map<PropertyId<?>, PropertyId<?>.Value> values) {
for (KeyId<?, ?> keyId : keyIdsByName.values()) {
if (keyId instanceof PropertyId) {
PropertyId<?> propertyId = (PropertyId<?>) keyId;
@@ -427,7 +471,7 @@ public class AsapConfigBuilder {
try {
assert propertyId != null;
- set(propertyId, value, new EnvironmentLocation(envKey));
+ setString(propertyId, value, new EnvironmentLocation(envKey));
} catch (ConfigurationException e) {
exceptions.appendException(e);
}
@@ -450,6 +494,10 @@ public class AsapConfigBuilder {
return this;
}
+ //
+ // Default location
+ //
+
public void pushDefaultLocation(@Nonnull Location location) {
defaultLocations.push(location);
}
@@ -458,4 +506,221 @@ public class AsapConfigBuilder {
assert defaultLocations.size() > 1;
defaultLocations.pop();
}
+
+ @Nonnull
+ public <T> AsapConfigBuilder set(@Nonnull ObjectId<T> objectId, @Nonnull T value) {
+ return set(objectId, value, defaultLocations.peek());
+ }
+
+ @Nonnull
+ public <T> AsapConfigBuilder set(@Nonnull String name, @Nonnull T value)
+ throws UnknownPropertyNameException, PropertyIdException {
+ return set(name, value, defaultLocations.peek());
+ }
+
+ @Nonnull
+ public <T> AsapConfigBuilder set(@Nonnull PropertyId<T> propertyId, @Nonnull T value)
+ throws PropertyIdException {
+ return set(propertyId, value, defaultLocations.peek());
+ }
+
+ @Nonnull
+ public AsapConfigBuilder setString(@Nonnull PropertyId<?> propertyId, @Nonnull String value)
+ throws PropertyIdException {
+ return setString(propertyId, value, defaultLocations.peek());
+ }
+
+ @Nonnull
+ public AsapConfigBuilder setString(@Nonnull String name, @Nonnull String value)
+ throws UnknownPropertyNameException, PropertyIdException {
+ return setString(name, value, defaultLocations.peek());
+ }
+
+ //
+ // Commodity helper
+ //
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Boolean> propertyId, boolean value) {
+ try {
+ set(propertyId, Boolean.valueOf(value));
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Boolean> propertyId, boolean value,
+ @Nonnull Location location) {
+ try {
+ set(propertyId, Boolean.valueOf(value), location);
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Byte> propertyId, byte value) {
+ try {
+ set(propertyId, Byte.valueOf(value));
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Byte> propertyId, byte value,
+ @Nonnull Location location) {
+ try {
+ set(propertyId, Byte.valueOf(value), location);
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Short> propertyId, short value) {
+ try {
+ set(propertyId, Short.valueOf(value));
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Short> propertyId, short value,
+ @Nonnull Location location) {
+ try {
+ set(propertyId, Short.valueOf(value), location);
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Character> propertyId, char value) {
+ try {
+ set(propertyId, Character.valueOf(value));
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Character> propertyId, char value,
+ @Nonnull Location location) {
+ try {
+ set(propertyId, Character.valueOf(value), location);
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Integer> propertyId, int value) {
+ try {
+ set(propertyId, Integer.valueOf(value));
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Integer> propertyId, int value,
+ @Nonnull Location location) {
+ try {
+ set(propertyId, Integer.valueOf(value), location);
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Long> propertyId, long value) {
+ try {
+ set(propertyId, Long.valueOf(value));
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Long> propertyId, long value,
+ @Nonnull Location location) {
+ try {
+ set(propertyId, Long.valueOf(value), location);
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Float> propertyId, float value) {
+ try {
+ set(propertyId, Float.valueOf(value));
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Float> propertyId, float value,
+ @Nonnull Location location) {
+ try {
+ set(propertyId, Float.valueOf(value), location);
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Double> propertyId, double value) {
+ try {
+ set(propertyId, Double.valueOf(value));
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public AsapConfigBuilder set(@Nonnull PropertyId<Double> propertyId, double value,
+ @Nonnull Location location) {
+ try {
+ set(propertyId, Double.valueOf(value), location);
+ } catch (PropertyIdException e) {
+ throw new AssertionError();
+ }
+
+ return this;
+ }
}
diff --git a/sched/src/com/android/sched/util/config/Config.java b/sched/src/com/android/sched/util/config/Config.java
index 40faa5c..2bbf884 100644
--- a/sched/src/com/android/sched/util/config/Config.java
+++ b/sched/src/com/android/sched/util/config/Config.java
@@ -17,18 +17,22 @@
package com.android.sched.util.config;
import com.android.sched.util.config.id.KeyId;
+import com.android.sched.util.config.id.ObjectId;
import com.android.sched.util.config.id.PropertyId;
import java.util.Collection;
import javax.annotation.Nonnull;
-
/**
- * The class that deals with configuration properties in 'get' mode.
+ * The interface that deals with configuration properties in 'get' mode.
*/
public interface Config {
@Nonnull
+ public <T> T get(@Nonnull PropertyId<T> propertyId);
+ @Nonnull
+ public <T> T get(@Nonnull ObjectId<T> objectId);
+ @Nonnull
public <T, S> T get(@Nonnull KeyId<T, S> keyId);
@Nonnull
public <T> String getAsString(@Nonnull PropertyId<T> propertyId);
diff --git a/sched/src/com/android/sched/util/config/ConfigChecker.java b/sched/src/com/android/sched/util/config/ConfigChecker.java
index 4f151c8..781d77a 100644
--- a/sched/src/com/android/sched/util/config/ConfigChecker.java
+++ b/sched/src/com/android/sched/util/config/ConfigChecker.java
@@ -18,10 +18,10 @@ package com.android.sched.util.config;
import com.android.sched.util.codec.CodecContext;
import com.android.sched.util.codec.ParsingException;
-import com.android.sched.util.codec.StringCodec;
import com.android.sched.util.config.id.KeyId;
import com.android.sched.util.config.id.ObjectId;
import com.android.sched.util.config.id.PropertyId;
+import com.android.sched.util.config.id.PropertyId.Value;
import java.util.HashMap;
import java.util.Map;
@@ -35,14 +35,15 @@ public class ConfigChecker {
@Nonnull
private final CodecContext context;
@Nonnull
- private final Map<PropertyId<?>, String> stringValuesById = new HashMap<PropertyId<?>, String>();
+ private final Map<PropertyId<?>, PropertyId<?>.Value> values =
+ new HashMap<PropertyId<?>, PropertyId<?>.Value>();
@Nonnull
- private final Map<KeyId<?, ?>, Object> instanceValuesById = new HashMap<KeyId<?, ?>, Object>();
+ private final Map<KeyId<?, ?>, Object> instances = new HashMap<KeyId<?, ?>, Object>();
@Nonnull
- private final Map<KeyId<?, ?>, Location> locationsById =
+ private final Map<KeyId<?, ?>, Location> locations =
new HashMap<KeyId<?, ?>, Location>();
@Nonnull
- private final Map<KeyId<?, ?>, String> droppedById = new HashMap<KeyId<?, ?>, String>();
+ private final Map<KeyId<?, ?>, String> dropped = new HashMap<KeyId<?, ?>, String>();
/**
* @param context Context for parsers
@@ -50,57 +51,50 @@ public class ConfigChecker {
* @param instanceValues All the property values as objects.
*/
ConfigChecker(@Nonnull CodecContext context,
- @Nonnull Map<PropertyId<?>, String> stringValues,
+ @Nonnull Map<PropertyId<?>, PropertyId<?>.Value> stringValues,
@Nonnull Map<ObjectId<?>, Object> instanceValues,
@Nonnull Map<KeyId<?, ?>, Location> locationsById) {
this.context = context;
- this.stringValuesById.putAll(stringValues);
- this.instanceValuesById.putAll(instanceValues);
- this.locationsById.putAll(locationsById);
+ this.values.putAll(stringValues);
+ this.instances.putAll(instanceValues);
+ this.locations.putAll(locationsById);
}
@Nonnull
- public synchronized <T> T parse(@Nonnull PropertyId<T> propertyId) throws PropertyIdException
- {
- @SuppressWarnings("unchecked")
- T instance = (T) instanceValuesById.get(propertyId);
-
- if (instance == null) {
- String value = getRawValue(propertyId);
- try {
- StringCodec<T> parser = propertyId.getCodec();
-
- instance = parser.checkString(context, value);
- if (instance == null) {
- instance = parser.parseString(context, value);
- }
+ public synchronized <T> T parse(@Nonnull PropertyId<T> propertyId) throws PropertyIdException {
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ PropertyId<T>.Value value = (PropertyId.Value) values.get(propertyId);
- instanceValuesById.put(propertyId, instance);
- stringValuesById.remove(propertyId);
- } catch (ParsingException e) {
- throw new PropertyIdException(propertyId, getLocation(propertyId), e);
- }
+ if (value == null) {
+ throw new MissingPropertyException(propertyId);
}
- return instance;
+ try {
+ value.check(context);
+ return value.getObject(context);
+ } catch (ParsingException e) {
+ throw new PropertyIdException(propertyId, getLocation(propertyId), e);
+ }
}
public synchronized <T, S> void check(@Nonnull KeyId<T, S> keyId) throws PropertyIdException {
- if (instanceValuesById.get(keyId) == null) {
+ if (instances.get(keyId) == null) {
if (keyId instanceof PropertyId) {
@SuppressWarnings("unchecked")
PropertyId<T> propertyId = (PropertyId<T>) keyId;
- String value = getRawValue(propertyId);
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ PropertyId<T>.Value value = (PropertyId.Value) values.get(propertyId);
+
+ if (value == null) {
+ throw new MissingPropertyException(propertyId);
+ }
+
try {
- T instance = propertyId.getCodec().checkString(context, value);
- if (instance != null) {
- instanceValuesById.put(propertyId, instance);
- stringValuesById.remove(keyId);
- }
+ value.check(context);
} catch (ParsingException e) {
throw new PropertyIdException(propertyId, getLocation(propertyId), e);
}
-
} else {
assert keyId instanceof ObjectId;
@@ -114,41 +108,42 @@ public class ConfigChecker {
@Nonnull
public <T> String getRawValue(@Nonnull PropertyId<T> propertyId)
throws MissingPropertyException {
- String value = stringValuesById.get(propertyId);
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ PropertyId<T>.Value value = (Value) values.get(propertyId);
if (value == null) {
throw new MissingPropertyException(propertyId);
}
- return value;
+ return value.getString();
}
@Nonnull
public Map<KeyId<?, ?>, Object> getInstances() {
- return instanceValuesById;
+ return instances;
}
@Nonnull
- public Map<PropertyId<?>, String> getStrings() {
- return stringValuesById;
+ public Map<PropertyId<?>, PropertyId<?>.Value> getValues() {
+ return values;
}
@Nonnull
public Map<KeyId<?, ?>, String> getDropCauses() {
- return droppedById;
+ return dropped;
}
@Nonnull
public Location getLocation(@Nonnull KeyId<?, ?> keyId) {
- assert locationsById.get(keyId) != null;
+ assert locations.get(keyId) != null;
- return locationsById.get(keyId);
+ return locations.get(keyId);
}
public void remove(@Nonnull KeyId<?, ?> keyId, @Nonnull String cause) {
- stringValuesById.remove(keyId);
- instanceValuesById.remove(keyId);
- locationsById.remove(keyId);
- droppedById.put(keyId, cause);
+ values.remove(keyId);
+ instances.remove(keyId);
+ locations.remove(keyId);
+ dropped.put(keyId, cause);
}
}
diff --git a/sched/src/com/android/sched/util/config/ConfigDebug.java b/sched/src/com/android/sched/util/config/ConfigDebug.java
index f7b5a94..db926d1 100644
--- a/sched/src/com/android/sched/util/config/ConfigDebug.java
+++ b/sched/src/com/android/sched/util/config/ConfigDebug.java
@@ -18,6 +18,7 @@ package com.android.sched.util.config;
import com.android.sched.util.codec.CodecContext;
import com.android.sched.util.config.id.KeyId;
+import com.android.sched.util.config.id.ObjectId;
import com.android.sched.util.config.id.PropertyId;
import com.android.sched.util.log.LoggerFactory;
@@ -47,16 +48,29 @@ class ConfigDebug extends ConfigImpl {
}
};
- ConfigDebug(@Nonnull CodecContext context, @Nonnull Map<PropertyId<?>, String> stringValues,
- @Nonnull Map<KeyId<?, ?>, Object> instanceValues,
+ ConfigDebug(@Nonnull CodecContext context,
+ @Nonnull Map<PropertyId<?>, PropertyId<?>.Value> values,
+ @Nonnull Map<KeyId<?, ?>, Object> instances,
@Nonnull Map<KeyId<?, ?>, String> dropCauses) {
- super(context, stringValues, instanceValues);
+ super(context, values, instances);
this.dropCauses = new HashMap<KeyId<?, ?>, String>(dropCauses);
}
@Override
@Nonnull
+ public synchronized <T> T get(@Nonnull PropertyId<T> propertyId) {
+ return get((KeyId<T, ?>) propertyId);
+ }
+
+ @Override
+ @Nonnull
+ public synchronized <T> T get(@Nonnull ObjectId<T> objectId) {
+ return get((KeyId<T, ?>) objectId);
+ }
+
+ @Override
+ @Nonnull
public <T, S> T get(@Nonnull KeyId<T, S> keyId) {
Stack<KeyId<?, ?>> localKeyIds = keyIds.get();
diff --git a/sched/src/com/android/sched/util/config/ConfigImpl.java b/sched/src/com/android/sched/util/config/ConfigImpl.java
index 00a1bce..d3d6ee9 100644
--- a/sched/src/com/android/sched/util/config/ConfigImpl.java
+++ b/sched/src/com/android/sched/util/config/ConfigImpl.java
@@ -26,71 +26,110 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
* Implementation of a fully built {@code Config}.
*/
-class ConfigImpl implements Config {
+class ConfigImpl implements Config, InternalConfig {
@Nonnull
private final CodecContext context;
@Nonnull
- private final Map<PropertyId<?>, String> stringValuesById = new HashMap<PropertyId<?>, String>();
+ private final Map<PropertyId<?>, PropertyId<?>.Value> valuesById =
+ new HashMap<PropertyId<?>, PropertyId<?>.Value>();
@Nonnull
- private final Map<KeyId<?, ?>, Object> instanceValuesById = new HashMap<KeyId<?, ?>, Object>();
+ private final Map<KeyId<?, ?>, Object> instancesById = new HashMap<KeyId<?, ?>, Object>();
/**
* @param context Context for parsers
- * @param stringValues All the property values as {@code String} objects.
- * @param instanceValues All the property values as objects.
+ * @param values All the property values as {@code String} objects.
+ * @param instances All the property values as objects.
*/
- ConfigImpl(@Nonnull CodecContext context, @Nonnull Map<PropertyId<?>, String> stringValues,
- @Nonnull Map<KeyId<?, ?>, Object> instanceValues) {
+ ConfigImpl(@Nonnull CodecContext context, @Nonnull Map<PropertyId<?>, PropertyId<?>.Value> values,
+ @Nonnull Map<KeyId<?, ?>, Object> instances) {
this.context = context;
- this.stringValuesById.putAll(stringValues);
- this.instanceValuesById.putAll(instanceValues);
+ this.valuesById.putAll(values);
+ this.instancesById.putAll(instances);
}
@Override
@Nonnull
- public synchronized <T, S> T get(@Nonnull KeyId<T, S> keyId) {
- @SuppressWarnings("unchecked")
- T instance = (T) instanceValuesById.get(keyId);
+ public <T> T get(@Nonnull PropertyId<T> propertyId) {
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ PropertyId<T>.Value value = (PropertyId.Value) valuesById.get(propertyId);
+
+ if (value == null) {
+ throw new ConfigurationError("Property '" + propertyId.getName()
+ + "' is unknown (see annotation @" + HasKeyId.class.getSimpleName()
+ + " or requiredIf expression)");
+ }
- if (instance == null) {
- if (keyId instanceof PropertyId) {
- @SuppressWarnings("unchecked")
- PropertyId<T> propertyId = (PropertyId<T>) keyId;
-
- String value = stringValuesById.get(propertyId);
- if (value == null) {
- throw new ConfigurationError("Property '" + propertyId.getName()
- + "' is unknown (see annotation @" + HasKeyId.class.getSimpleName()
- + " or requiredIf expression)");
- }
+ return value.getObject(context);
+ }
- instance = propertyId.getCodec().parseString(context, value);
- instanceValuesById.put(propertyId, instance);
- stringValuesById.remove(propertyId);
- } else {
- @SuppressWarnings("unchecked")
- ObjectId<T> objectId = (ObjectId<T>) keyId;
+ @Override
+ @CheckForNull
+ public <T> T getObjectIfAny(@Nonnull PropertyId<T> propertyId) {
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ PropertyId<T>.Value value = (PropertyId.Value) valuesById.get(propertyId);
+
+ if (value == null) {
+ throw new ConfigurationError("Property '" + propertyId.getName()
+ + "' is unknown (see annotation @" + HasKeyId.class.getSimpleName()
+ + " or requiredIf expression)");
+ }
- instance = objectId.createObject();
- instanceValuesById.put(objectId, instance);
- }
+ return value.getObjectIfAny();
+ }
+
+ @Override
+ @Nonnull
+ public <T> String getAsString(@Nonnull PropertyId<T> propertyId) {
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ PropertyId<T>.Value value = (PropertyId.Value) valuesById.get(propertyId);
+
+ if (value == null) {
+ throw new ConfigurationError("Property '" + propertyId.getName()
+ + "' is unknown (see annotation @" + HasKeyId.class.getSimpleName()
+ + " or requiredIf expression)");
+ }
+
+ return value.getString();
+ }
+
+ @Override
+ @Nonnull
+ public synchronized <T> T get(@Nonnull ObjectId<T> objectId) {
+ @SuppressWarnings("unchecked")
+ T instance = (T) instancesById.get(objectId);
+
+ if (instance == null) {
+ instance = objectId.createObject();
+ instancesById.put(objectId, instance);
}
return instance;
}
+ @SuppressWarnings("unchecked")
+ @Override
+ @Nonnull
+ public <T, S> T get(@Nonnull KeyId<T, S> keyId) {
+ if (keyId instanceof PropertyId) {
+ return get((PropertyId<T>) keyId);
+ } else {
+ return get((ObjectId<T>) keyId);
+ }
+ }
+
@Override
@Nonnull
public Collection<PropertyId<?>> getPropertyIds() {
ArrayList<PropertyId<?>> result =
- new ArrayList<PropertyId<?>>(instanceValuesById.size() + stringValuesById.size());
+ new ArrayList<PropertyId<?>>(instancesById.size() + valuesById.size());
- for (KeyId<?, ?> keyId : stringValuesById.keySet()) {
+ for (KeyId<?, ?> keyId : valuesById.keySet()) {
if (keyId.isPublic()) {
if (keyId instanceof PropertyId) {
result.add((PropertyId<?>) keyId);
@@ -98,7 +137,7 @@ class ConfigImpl implements Config {
}
}
- for (KeyId<?, ?> keyId : instanceValuesById.keySet()) {
+ for (KeyId<?, ?> keyId : instancesById.keySet()) {
if (keyId.isPublic()) {
if (keyId instanceof PropertyId) {
result.add((PropertyId<?>) keyId);
@@ -108,25 +147,4 @@ class ConfigImpl implements Config {
return result;
}
-
- @Override
- @Nonnull
- public <T> String getAsString(@Nonnull PropertyId<T> propertyId) {
- String result;
-
- result = stringValuesById.get(propertyId);
- if (result == null) {
- @SuppressWarnings("unchecked")
- T instance = (T) instanceValuesById.get(propertyId);
- if (instance == null) {
- throw new ConfigurationError("Property '" + propertyId.getName()
- + "' is unknown (see annotation @" + HasKeyId.class.getSimpleName()
- + " or requiredIf expression)");
- }
-
- result = propertyId.getCodec().formatValue(instance);
- }
-
- return result;
- }
}
diff --git a/sched/src/com/android/sched/util/config/ConfigurationError.java b/sched/src/com/android/sched/util/config/ConfigurationError.java
index 9ca2b2b..fef0795 100644
--- a/sched/src/com/android/sched/util/config/ConfigurationError.java
+++ b/sched/src/com/android/sched/util/config/ConfigurationError.java
@@ -16,6 +16,7 @@
package com.android.sched.util.config;
+import com.android.sched.util.codec.CheckingException;
import com.android.sched.util.codec.ParsingException;
import javax.annotation.Nonnull;
@@ -43,4 +44,8 @@ public class ConfigurationError extends Error {
public ConfigurationError(@Nonnull ParsingException e) {
super(e.getMessage(), e);
}
+
+ public ConfigurationError(@Nonnull CheckingException e) {
+ super(e.getMessage(), e);
+ }
}
diff --git a/sched/src/com/android/sched/util/config/GatherConfigBuilder.java b/sched/src/com/android/sched/util/config/GatherConfigBuilder.java
index b923541..133ef88 100644
--- a/sched/src/com/android/sched/util/config/GatherConfigBuilder.java
+++ b/sched/src/com/android/sched/util/config/GatherConfigBuilder.java
@@ -54,7 +54,21 @@ public class GatherConfigBuilder {
}
@Nonnull
- public GatherConfigBuilder set(@Nonnull String name, @Nonnull String value) {
+ public GatherConfigBuilder setString(@Nonnull String name, @Nonnull String value) {
+ try {
+ builder.setString(name, value);
+ } catch (PropertyIdException e) {
+ exceptions.appendException(e);
+ } catch (UnknownPropertyNameException e) {
+ exceptions.appendException(e);
+ }
+
+ return this;
+ }
+
+
+ @Nonnull
+ public <T> GatherConfigBuilder set(@Nonnull String name, @Nonnull T value) {
try {
builder.set(name, value);
} catch (PropertyIdException e) {
@@ -67,9 +81,24 @@ public class GatherConfigBuilder {
}
@Nonnull
- public GatherConfigBuilder set(
+ public GatherConfigBuilder setString(
@Nonnull String name, @Nonnull String value, @Nonnull Location location) {
try {
+ builder.setString(name, value, location);
+ } catch (UnknownPropertyNameException e) {
+ exceptions.appendException(e);
+ } catch (PropertyIdException e) {
+ exceptions.appendException(e);
+ }
+
+ return this;
+ }
+
+
+ @Nonnull
+ public <T> GatherConfigBuilder set(
+ @Nonnull String name, @Nonnull T value, @Nonnull Location location) {
+ try {
builder.set(name, value, location);
} catch (UnknownPropertyNameException e) {
exceptions.appendException(e);
@@ -81,7 +110,20 @@ public class GatherConfigBuilder {
}
@Nonnull
- public GatherConfigBuilder set(@Nonnull PropertyId<?> propertyId, @Nonnull String value) {
+ public GatherConfigBuilder setString(@Nonnull PropertyId<?> propertyId, @Nonnull String value) {
+ try {
+ builder.setString(propertyId, value);
+ } catch (UnknownPropertyIdException e) {
+ exceptions.appendException(e);
+ } catch (PropertyIdException e) {
+ exceptions.appendException(e);
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public <T> GatherConfigBuilder set(@Nonnull PropertyId<T> propertyId, @Nonnull T value) {
try {
builder.set(propertyId, value);
} catch (UnknownPropertyIdException e) {
@@ -94,9 +136,23 @@ public class GatherConfigBuilder {
}
@Nonnull
- public GatherConfigBuilder set(
+ public GatherConfigBuilder setString(
@Nonnull PropertyId<?> propertyId, @Nonnull String value, @Nonnull Location location) {
try {
+ builder.setString(propertyId, value, location);
+ } catch (UnknownPropertyIdException e) {
+ exceptions.appendException(e);
+ } catch (PropertyIdException e) {
+ exceptions.appendException(e);
+ }
+
+ return this;
+ }
+
+ @Nonnull
+ public <T> GatherConfigBuilder set(
+ @Nonnull PropertyId<T> propertyId, @Nonnull T value, @Nonnull Location location) {
+ try {
builder.set(propertyId, value, location);
} catch (UnknownPropertyIdException e) {
exceptions.appendException(e);
@@ -151,12 +207,18 @@ public class GatherConfigBuilder {
*/
@Nonnull
public Config build() throws ConfigurationException {
+ Config config;
+
try {
- return builder.build();
+ config = builder.build();
} catch (ConfigurationException e) {
exceptions.appendException(e);
throw exceptions.getException();
}
+
+ exceptions.throwIfNecessary();
+
+ return config;
}
@Nonnull
@@ -180,6 +242,10 @@ public class GatherConfigBuilder {
return this;
}
+ //
+ // Default location
+ //
+
public void pushDefaultLocation(@Nonnull Location location) {
builder.pushDefaultLocation(location);
}
@@ -187,4 +253,128 @@ public class GatherConfigBuilder {
public void popDefaultLocation() {
builder.popDefaultLocation();
}
+
+ //
+ // Commodity helper
+ //
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Boolean> propertyId, boolean value) {
+ set(propertyId, Boolean.valueOf(value));
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Boolean> propertyId, boolean value,
+ @Nonnull Location location) {
+ set(propertyId, Boolean.valueOf(value), location);
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Byte> propertyId, byte value) {
+ set(propertyId, Byte.valueOf(value));
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Byte> propertyId, byte value,
+ @Nonnull Location location) {
+ set(propertyId, Byte.valueOf(value), location);
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Short> propertyId, short value) {
+ set(propertyId, Short.valueOf(value));
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Short> propertyId, short value,
+ @Nonnull Location location) {
+ set(propertyId, Short.valueOf(value), location);
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Character> propertyId, char value) {
+ set(propertyId, Character.valueOf(value));
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Character> propertyId, char value,
+ @Nonnull Location location) {
+ set(propertyId, Character.valueOf(value), location);
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Integer> propertyId, int value) {
+ set(propertyId, Integer.valueOf(value));
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Integer> propertyId, int value,
+ @Nonnull Location location) {
+ set(propertyId, Integer.valueOf(value), location);
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Long> propertyId, long value) {
+ set(propertyId, Long.valueOf(value));
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Long> propertyId, long value,
+ @Nonnull Location location) {
+ set(propertyId, Long.valueOf(value), location);
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Float> propertyId, float value) {
+ set(propertyId, Float.valueOf(value));
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Float> propertyId, float value,
+ @Nonnull Location location) {
+ set(propertyId, Float.valueOf(value), location);
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Double> propertyId, double value) {
+ set(propertyId, Double.valueOf(value));
+
+ return this;
+ }
+
+ @Nonnull
+ public GatherConfigBuilder set(@Nonnull PropertyId<Double> propertyId, double value,
+ @Nonnull Location location) {
+ set(propertyId, Double.valueOf(value), location);
+
+ return this;
+ }
}
diff --git a/sched/src/com/android/sched/util/config/InternalConfig.java b/sched/src/com/android/sched/util/config/InternalConfig.java
new file mode 100644
index 0000000..0f96a98
--- /dev/null
+++ b/sched/src/com/android/sched/util/config/InternalConfig.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.util.config;
+
+import com.android.sched.util.config.id.PropertyId;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * The interface that deals with configuration properties in private 'get' mode. This interface is
+ * for private use only (config framework itself).
+ */
+public interface InternalConfig {
+ @CheckForNull
+ public <T> T getObjectIfAny(@Nonnull PropertyId<T> propertyId);
+}
diff --git a/sched/src/com/android/sched/util/config/ThreadConfig.java b/sched/src/com/android/sched/util/config/ThreadConfig.java
index df8cfa5..da532fd 100644
--- a/sched/src/com/android/sched/util/config/ThreadConfig.java
+++ b/sched/src/com/android/sched/util/config/ThreadConfig.java
@@ -16,7 +16,14 @@
package com.android.sched.util.config;
-import com.android.sched.util.config.id.KeyId;
+import com.android.sched.util.config.id.ObjectId;
+import com.android.sched.util.config.id.PropertyId;
+import com.android.sched.util.log.Tracer;
+import com.android.sched.util.log.TracerFactory;
+import com.android.sched.util.log.stats.Counter;
+import com.android.sched.util.log.stats.CounterImpl;
+import com.android.sched.util.log.stats.StatisticId;
+import com.android.sched.util.log.tracer.TracerEventType;
import javax.annotation.Nonnull;
@@ -25,6 +32,11 @@ import javax.annotation.Nonnull;
*/
public class ThreadConfig {
@Nonnull
+ public static final StatisticId<Counter> TLS_READ = new StatisticId<Counter>(
+ "sched.config.tls.read", "Reading TLS to get current config",
+ CounterImpl.class, Counter.class);
+
+ @Nonnull
private static final Config unitializedConfig = new UninitializedConfig();
@Nonnull
@@ -37,8 +49,27 @@ public class ThreadConfig {
};
@Nonnull
- public static <T, S> T get(@Nonnull KeyId<T, S> keyId) {
- return threadLocalConfig.get().get(keyId);
+ public static <T> T get(@Nonnull PropertyId<T> propertyId) {
+ Config config = threadLocalConfig.get();
+ updateStatistic(config);
+
+ return config.get(propertyId);
+ }
+
+ @Nonnull
+ public static <T> T get(@Nonnull ObjectId<T> objectId) {
+ Config config = threadLocalConfig.get();
+ updateStatistic(config);
+
+ return config.get(objectId);
+ }
+
+ private static void updateStatistic(@Nonnull Config config) {
+ Tracer tracer = ((InternalConfig) config).<Tracer> getObjectIfAny(TracerFactory.TRACER);
+
+ if (tracer != null && tracer.getCurrentEventType() != TracerEventType.NOEVENT) {
+ tracer.getStatistic(TLS_READ).incValue();
+ }
}
@Nonnull
diff --git a/sched/src/com/android/sched/util/config/UninitializedConfig.java b/sched/src/com/android/sched/util/config/UninitializedConfig.java
index f87e628..b6c8e7f 100644
--- a/sched/src/com/android/sched/util/config/UninitializedConfig.java
+++ b/sched/src/com/android/sched/util/config/UninitializedConfig.java
@@ -17,16 +17,29 @@
package com.android.sched.util.config;
import com.android.sched.util.config.id.KeyId;
+import com.android.sched.util.config.id.ObjectId;
import com.android.sched.util.config.id.PropertyId;
import java.util.Collection;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
* This object represents a {@link Config} which has not been created by the builder.
*/
-class UninitializedConfig implements Config {
+class UninitializedConfig implements Config, InternalConfig {
+ @Override
+ @Nonnull
+ public <T> T get(@Nonnull PropertyId<T> propertyId) {
+ throw new ConfigurationError("Configuration has not been initialized");
+ }
+
+ @Override
+ @Nonnull
+ public <T> T get(@Nonnull ObjectId<T> objectId) {
+ throw new ConfigurationError("Configuration has not been initialized");
+ }
@Override
@Nonnull
@@ -45,4 +58,10 @@ class UninitializedConfig implements Config {
public Collection<PropertyId<?>> getPropertyIds() {
throw new ConfigurationError("Configuration has not been initialized");
}
+
+ @Override
+ @CheckForNull
+ public <T> T getObjectIfAny(@Nonnull PropertyId<T> propertyId) {
+ throw new ConfigurationError("Configuration has not been initialized");
+ }
}
diff --git a/sched/src/com/android/sched/util/config/VariableDoesNotMatchConfigurationException.java b/sched/src/com/android/sched/util/config/VariableDoesNotMatchConfigurationException.java
index 06c711c..788e852 100644
--- a/sched/src/com/android/sched/util/config/VariableDoesNotMatchConfigurationException.java
+++ b/sched/src/com/android/sched/util/config/VariableDoesNotMatchConfigurationException.java
@@ -25,7 +25,7 @@ public class VariableDoesNotMatchConfigurationException extends VariableConfigur
private static final long serialVersionUID = 1L;
public VariableDoesNotMatchConfigurationException(@Nonnull String variable) {
- super(variable, "Environment variable '" + variable + " does not match any properties");
+ super(variable, "Environment variable '" + variable + "' does not match any properties");
}
public VariableDoesNotMatchConfigurationException(
diff --git a/sched/src/com/android/sched/util/config/VariableMatchesSeveralConfigurationException.java b/sched/src/com/android/sched/util/config/VariableMatchesSeveralConfigurationException.java
index f6eaab6..1e00409 100644
--- a/sched/src/com/android/sched/util/config/VariableMatchesSeveralConfigurationException.java
+++ b/sched/src/com/android/sched/util/config/VariableMatchesSeveralConfigurationException.java
@@ -31,7 +31,7 @@ public class VariableMatchesSeveralConfigurationException extends VariableConfig
public VariableMatchesSeveralConfigurationException(
@Nonnull String variable, @Nonnull PropertyId<?> propertyId) {
- super(variable, "Environment variable '" + variable + " matches several properties: '"
+ super(variable, "Environment variable '" + variable + "' matches several properties: '"
+ propertyId.getName() + "'");
this.propertyId = propertyId;
}
diff --git a/sched/src/com/android/sched/util/config/ZipLocation.java b/sched/src/com/android/sched/util/config/ZipLocation.java
index 3a6d9be..af78749 100644
--- a/sched/src/com/android/sched/util/config/ZipLocation.java
+++ b/sched/src/com/android/sched/util/config/ZipLocation.java
@@ -30,11 +30,11 @@ public class ZipLocation extends Location {
private final Location archive;
@Nonnull
- private final String pathInArchive;
+ private final String entryName;
public ZipLocation(@Nonnull Location archive, @Nonnull ZipEntry entry) {
this.archive = archive;
- this.pathInArchive = '/' + entry.getName();
+ this.entryName = entry.getName();
}
@Override
@@ -46,7 +46,7 @@ public class ZipLocation extends Location {
sb.append(archive.getDescription()).append(", ");
}
- return sb.append("entry '").append(pathInArchive).append('\'').toString();
+ return sb.append("entry '/").append(entryName).append('\'').toString();
}
@Nonnull
@@ -54,22 +54,20 @@ public class ZipLocation extends Location {
return archive;
}
- /**
- * @return the pathInArchive
- */
- public String getPathInArchive() {
- return pathInArchive;
+ @Nonnull
+ public String getEntryName() {
+ return entryName;
}
@Override
public final boolean equals(Object obj) {
return obj instanceof ZipLocation
&& ((ZipLocation) obj).archive.equals(archive)
- && ((ZipLocation) obj).getPathInArchive().equals(pathInArchive);
+ && ((ZipLocation) obj).entryName.equals(entryName);
}
@Override
public final int hashCode() {
- return archive.hashCode() ^ pathInArchive.hashCode();
+ return archive.hashCode() ^ entryName.hashCode();
}
}
diff --git a/sched/src/com/android/sched/util/config/id/BooleanPropertyId.java b/sched/src/com/android/sched/util/config/id/BooleanPropertyId.java
index ebe2399..a97bd45 100644
--- a/sched/src/com/android/sched/util/config/id/BooleanPropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/BooleanPropertyId.java
@@ -52,6 +52,21 @@ public class BooleanPropertyId extends PropertyId<Boolean> {
@Override
@Nonnull
+ public BooleanPropertyId addDefaultValue (@Nonnull Boolean defaultValue) {
+ super.addDefaultValue(defaultValue);
+
+ return this;
+ }
+
+ @Nonnull
+ public BooleanPropertyId addDefaultValue (boolean defaultValue) {
+ super.addDefaultValue(Boolean.valueOf(defaultValue));
+
+ return this;
+ }
+
+ @Override
+ @Nonnull
public BooleanPropertyId requiredIf(@Nonnull BooleanExpression expression) {
super.requiredIf(expression);
diff --git a/sched/src/com/android/sched/util/config/id/DoublePropertyId.java b/sched/src/com/android/sched/util/config/id/DoublePropertyId.java
index 786c9b2..111fd5e 100644
--- a/sched/src/com/android/sched/util/config/id/DoublePropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/DoublePropertyId.java
@@ -51,6 +51,21 @@ public class DoublePropertyId extends PropertyId<Double> {
@Override
@Nonnull
+ public DoublePropertyId addDefaultValue (@Nonnull Double defaultValue) {
+ super.addDefaultValue(defaultValue);
+
+ return this;
+ }
+
+ @Nonnull
+ public DoublePropertyId addDefaultValue (@Nonnull double defaultValue) {
+ super.addDefaultValue(Double.valueOf(defaultValue));
+
+ return this;
+ }
+
+ @Override
+ @Nonnull
public DoublePropertyId requiredIf(@Nonnull BooleanExpression expression) {
super.requiredIf(expression);
diff --git a/sched/src/com/android/sched/util/config/id/EnumPropertyId.java b/sched/src/com/android/sched/util/config/id/EnumPropertyId.java
index 493f1e5..c209e3c 100644
--- a/sched/src/com/android/sched/util/config/id/EnumPropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/EnumPropertyId.java
@@ -51,6 +51,14 @@ public class EnumPropertyId<T extends Enum<T>> extends PropertyId<T> {
@Override
@Nonnull
+ public EnumPropertyId<T> addDefaultValue (@Nonnull T defaultValue) {
+ super.addDefaultValue(defaultValue);
+
+ return this;
+ }
+
+ @Override
+ @Nonnull
public EnumPropertyId<T> requiredIf(@Nonnull BooleanExpression expression) {
super.requiredIf(expression);
diff --git a/sched/src/com/android/sched/util/config/id/IntegerPropertyId.java b/sched/src/com/android/sched/util/config/id/IntegerPropertyId.java
index 4b584cd..ce03c10 100644
--- a/sched/src/com/android/sched/util/config/id/IntegerPropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/IntegerPropertyId.java
@@ -44,6 +44,20 @@ public class IntegerPropertyId extends LongPropertyId {
return this;
}
+ @Nonnull
+ public IntegerPropertyId addDefaultValue (@Nonnull Integer defaultValue) {
+ super.addDefaultValue(Long.valueOf(defaultValue.longValue()));
+
+ return this;
+ }
+
+ @Nonnull
+ public IntegerPropertyId addDefaultValue (@Nonnull int defaultValue) {
+ super.addDefaultValue(Long.valueOf(defaultValue));
+
+ return this;
+ }
+
@Override
@Nonnull
public IntegerPropertyId requiredIf(@Nonnull BooleanExpression expression) {
diff --git a/sched/src/com/android/sched/util/config/id/KeyId.java b/sched/src/com/android/sched/util/config/id/KeyId.java
index 40b157c..3576fab 100644
--- a/sched/src/com/android/sched/util/config/id/KeyId.java
+++ b/sched/src/com/android/sched/util/config/id/KeyId.java
@@ -21,9 +21,6 @@ import com.android.sched.util.config.PropertyIdException;
import com.android.sched.util.config.expression.BooleanExpression;
import com.android.sched.util.config.expression.PropertyNotRequiredException;
-import java.util.ArrayList;
-import java.util.List;
-
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -38,12 +35,6 @@ public abstract class KeyId<T, S> {
@Nonnull
private final String name;
- @CheckForNull
- private BooleanExpression requiredIf;
-
- @Nonnull
- private final List<S> defaultValues = new ArrayList<S>(2);
-
public KeyId(@Nonnull String name) {
this.name = name;
}
@@ -55,17 +46,8 @@ public abstract class KeyId<T, S> {
public abstract boolean isPublic();
- @Nonnull
- public KeyId<T, S> addDefaultValue(@Nonnull S defaultValue) {
- defaultValues.add(defaultValue);
-
- return this;
- }
-
- @Nonnull
- public List<S> getDefaultValues() {
- return defaultValues;
- }
+ @CheckForNull
+ private BooleanExpression requiredIf;
@Nonnull
public KeyId<T, S> requiredIf(@Nonnull BooleanExpression expression) {
diff --git a/sched/src/com/android/sched/util/config/id/ListPropertyId.java b/sched/src/com/android/sched/util/config/id/ListPropertyId.java
index 7f7c999..075fa00 100644
--- a/sched/src/com/android/sched/util/config/id/ListPropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/ListPropertyId.java
@@ -55,6 +55,15 @@ public class ListPropertyId<T> extends PropertyId<List<T>> {
return this;
}
+
+ @Override
+ @Nonnull
+ public ListPropertyId<T> addDefaultValue (@Nonnull List<T> defaultValue) {
+ super.addDefaultValue(defaultValue);
+
+ return this;
+ }
+
@Override
@Nonnull
public ListPropertyId<T> requiredIf(@Nonnull BooleanExpression expression) {
diff --git a/sched/src/com/android/sched/util/config/id/LongPropertyId.java b/sched/src/com/android/sched/util/config/id/LongPropertyId.java
index cb1e377..7f95102 100644
--- a/sched/src/com/android/sched/util/config/id/LongPropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/LongPropertyId.java
@@ -51,6 +51,21 @@ public class LongPropertyId extends PropertyId<Long> {
@Override
@Nonnull
+ public LongPropertyId addDefaultValue (@Nonnull Long defaultValue) {
+ super.addDefaultValue(defaultValue);
+
+ return this;
+ }
+
+ @Nonnull
+ public LongPropertyId addDefaultValue (@Nonnull long defaultValue) {
+ super.addDefaultValue(Long.valueOf(defaultValue));
+
+ return this;
+ }
+
+ @Override
+ @Nonnull
public LongPropertyId requiredIf(@Nonnull BooleanExpression expression) {
super.requiredIf(expression);
diff --git a/sched/src/com/android/sched/util/config/id/ProbabilityPropertyId.java b/sched/src/com/android/sched/util/config/id/ProbabilityPropertyId.java
index 1e173e1..f83165b 100644
--- a/sched/src/com/android/sched/util/config/id/ProbabilityPropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/ProbabilityPropertyId.java
@@ -45,6 +45,22 @@ public class ProbabilityPropertyId extends DoublePropertyId {
@Override
@Nonnull
+ public ProbabilityPropertyId addDefaultValue (@Nonnull Double defaultValue) {
+ super.addDefaultValue(defaultValue);
+
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public ProbabilityPropertyId addDefaultValue (@Nonnull double defaultValue) {
+ super.addDefaultValue(defaultValue);
+
+ return this;
+ }
+
+ @Override
+ @Nonnull
public ProbabilityPropertyId requiredIf(@Nonnull BooleanExpression expression) {
super.requiredIf(expression);
@@ -70,7 +86,7 @@ public class ProbabilityPropertyId extends DoublePropertyId {
}
private boolean checkRange(double value) {
- return value >= 0 && value <= 1;
+ return value >= 0.0 && value <= 1.0;
}
/**
diff --git a/sched/src/com/android/sched/util/config/id/PropertyId.java b/sched/src/com/android/sched/util/config/id/PropertyId.java
index 7e9fa28..280bf08 100644
--- a/sched/src/com/android/sched/util/config/id/PropertyId.java
+++ b/sched/src/com/android/sched/util/config/id/PropertyId.java
@@ -23,6 +23,9 @@ import com.android.sched.util.codec.StringCodec;
import com.android.sched.util.config.ConfigurationError;
import com.android.sched.util.config.expression.BooleanExpression;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -31,48 +34,55 @@ import javax.annotation.Nonnull;
* @param <T> Type of the configuration property.
*/
public class PropertyId<T> extends KeyId<T, String> {
-
@Nonnull
private final String description;
@Nonnull
- private final StringCodec<T> parser;
+ private final StringCodec<T> codec;
+ @Nonnull
+ private final List<Value> defaultValues = new ArrayList<Value>(1);
@CheckForNull
- private String defaultValue = null;
- private boolean defaultValueAvailable = false;
+ private Value defaultValue = null;
+ private boolean defaultValueAvailable = false;
private boolean isPublic = true;
public static <T> PropertyId<T> create(
- @Nonnull String name, @Nonnull String description, @Nonnull StringCodec<T> parser) {
- return new PropertyId<T>(name, description, parser);
+ @Nonnull String name, @Nonnull String description, @Nonnull StringCodec<T> codec) {
+ return new PropertyId<T>(name, description, codec);
}
- protected PropertyId(
- @Nonnull String name, @Nonnull String description, @Nonnull StringCodec<T> parser) {
+ protected PropertyId(@Nonnull String name, @Nonnull String description,
+ @Nonnull StringCodec<T> codec) {
super(name);
this.description = description;
- this.parser = parser;
+ this.codec = codec;
}
- @Override
@Nonnull
public PropertyId<T> addDefaultValue(@Nonnull String defaultValue) {
- super.addDefaultValue(defaultValue);
+ defaultValues.add(new Value(defaultValue));
+
+ return this;
+ }
+
+ @Nonnull
+ public PropertyId<T> addDefaultValue(@Nonnull T defaultValue) {
+ defaultValues.add(new Value(defaultValue));
return this;
}
@CheckForNull
- public String getDefaultValue(@Nonnull CodecContext context) {
+ public Value getDefaultValue(@Nonnull CodecContext context) {
if (!defaultValueAvailable) {
ParsingException lastException = null;
- for (String value : getDefaultValues()) {
+ for (Value value : getDefaultValues()) {
try {
- parser.checkString(context, value);
+ value.check(context);
defaultValue = value;
break;
} catch (ParsingException e) {
@@ -91,6 +101,11 @@ public class PropertyId<T> extends KeyId<T, String> {
}
@Nonnull
+ public List<Value> getDefaultValues() {
+ return defaultValues;
+ }
+
+ @Nonnull
public String getDescription() {
return description;
}
@@ -100,6 +115,7 @@ public class PropertyId<T> extends KeyId<T, String> {
return isPublic;
}
+ @Nonnull
public PropertyId<T> makePrivate() {
isPublic = false;
return this;
@@ -107,7 +123,7 @@ public class PropertyId<T> extends KeyId<T, String> {
@Nonnull
public StringCodec<T> getCodec() {
- return parser;
+ return codec;
}
@Override
@@ -118,4 +134,148 @@ public class PropertyId<T> extends KeyId<T, String> {
return this;
}
+ public class Value {
+ @Nonnull
+ private IValue<T> value;
+
+ public Value (@Nonnull T value) {
+ this.value = new IValueObject<T>(value);
+ }
+
+ public Value (@Nonnull String value) {
+ this.value = new IValueString(value);
+ }
+
+ public synchronized void check(@Nonnull CodecContext context) throws ParsingException {
+ value = value.check(context);
+ }
+
+ @Nonnull
+ public String getString() {
+ return value.getString();
+ }
+
+ @Nonnull
+ public synchronized T getObject(@Nonnull CodecContext context) {
+ value = value.getValueObject(context);
+
+ return ((IValueObject<T>) value).getObject();
+ }
+
+
+ @CheckForNull
+ public synchronized T getObjectIfAny() {
+ if (value instanceof IValueObject) {
+ return ((IValueObject<T>) value).getObject();
+ } else {
+ return null;
+ }
+ }
+ }
+
+ //
+ // Private IValue hierarchy
+ //
+
+ private static interface IValue<T> {
+ @Nonnull
+ public IValue<T> check(@Nonnull CodecContext context) throws ParsingException;
+
+ @Nonnull
+ public PropertyId<?>.IValueObject<T> getValueObject(@Nonnull CodecContext context);
+
+ @Nonnull
+ public String getString();
+ }
+
+ private class IValueString implements IValue<T> {
+ @Nonnull
+ private final String value;
+
+ public IValueString (@Nonnull String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String getString() {
+ return value;
+ }
+
+ @Override
+ @Nonnull
+ public IValue<T> check(@Nonnull CodecContext context) throws ParsingException {
+ T val = PropertyId.this.codec.checkString(context, value);
+
+ if (val != null) {
+ return new IValueObject<T>(val);
+ } else {
+ return new IValueCheckedString(value);
+ }
+ }
+
+ @Override
+ @Nonnull
+ public PropertyId<T>.IValueObject<T> getValueObject(@Nonnull CodecContext context) {
+ throw new AssertionError();
+ }
+ }
+
+ private class IValueCheckedString implements IValue<T> {
+ @Nonnull
+ private final String value;
+
+ private IValueCheckedString (@Nonnull String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String getString() {
+ return value;
+ }
+
+ @Override
+ @Nonnull
+ public IValue<T> check(@Nonnull CodecContext context) {
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public PropertyId<?>.IValueObject<T> getValueObject(@Nonnull CodecContext context) {
+ return new IValueObject<T>(PropertyId.this.codec.parseString(context, value));
+ }
+ }
+
+ private class IValueObject<T> implements IValue<T> {
+ @Nonnull
+ private final T value;
+
+ public IValueObject (@Nonnull T value) {
+ this.value = value;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ @Nonnull
+ public String getString() {
+ return ((PropertyId<T>) (PropertyId.this)).codec.formatValue(value);
+ }
+
+ @Override
+ @Nonnull
+ public IValue<T> check(@Nonnull CodecContext context) {
+ return this;
+ }
+
+ @Override
+ @Nonnull
+ public PropertyId<?>.IValueObject<T> getValueObject(@Nonnull CodecContext context) {
+ return this;
+ }
+
+ @Nonnull
+ public T getObject() {
+ return value;
+ }
+ }
}
diff --git a/sched/src/com/android/sched/util/log/EventType.java b/sched/src/com/android/sched/util/log/EventType.java
index 040d99a..418ccc3 100644
--- a/sched/src/com/android/sched/util/log/EventType.java
+++ b/sched/src/com/android/sched/util/log/EventType.java
@@ -20,6 +20,5 @@ package com.android.sched.util.log;
* Represents a event type of an event.
*/
public interface EventType {
- public String getColor();
public String getName();
} \ No newline at end of file
diff --git a/sched/src/com/android/sched/util/log/SchedEventType.java b/sched/src/com/android/sched/util/log/SchedEventType.java
index dd2352b..0344d6e 100644
--- a/sched/src/com/android/sched/util/log/SchedEventType.java
+++ b/sched/src/com/android/sched/util/log/SchedEventType.java
@@ -23,24 +23,15 @@ import javax.annotation.Nonnull;
* Represents a type of event whose performance is tracked
*/
public enum SchedEventType implements EventType {
- REFLECTIONS("Reflections", "Yellow"), //
- INSTANCIER("Schedulable instancier", "Blue"), //
- PLANBUILDER("Plan builder", "Red");
+ REFLECTIONS("Reflections"),
+ INSTANCIER("Schedulable instancier"),
+ PLANBUILDER("Plan builder");
@Nonnull
- private final String cssColor;
- @Nonnull
private final String name;
- SchedEventType(@Nonnull String name, @Nonnull String cssColor) {
+ SchedEventType(@Nonnull String name) {
this.name = name;
- this.cssColor = cssColor;
- }
-
- @Override
- @Nonnull
- public String getColor() {
- return cssColor;
}
@Override
diff --git a/sched/src/com/android/sched/util/log/StatisticOnlyTracer.java b/sched/src/com/android/sched/util/log/StatisticOnlyTracer.java
index da5323b..81095e5 100644
--- a/sched/src/com/android/sched/util/log/StatisticOnlyTracer.java
+++ b/sched/src/com/android/sched/util/log/StatisticOnlyTracer.java
@@ -36,11 +36,13 @@ import com.android.sched.util.table.ReportPrinterFactory;
import com.android.sched.util.table.SimpleTable;
import com.android.sched.util.table.Table;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -48,6 +50,7 @@ import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -147,7 +150,7 @@ public final class StatisticOnlyTracer implements Tracer {
@Override
@Nonnull
public String toString() {
- return "Dummy";
+ return "Singleton";
}
@Override
@@ -221,7 +224,7 @@ public final class StatisticOnlyTracer implements Tracer {
@Override
@Nonnull
public EventType getCurrentEventType() {
- return TracerEventType.NOEVENT;
+ return TracerEventType.SINGLETON;
}
@Override
@@ -246,77 +249,116 @@ public final class StatisticOnlyTracer implements Tracer {
objects = new HashMap<
Class<? extends ObjectWatcher<?>>, WeakHashMap<Object, ObjectWatcher<Object>>>();
+ // Map a class C to a list of watcher classes that watch instances of type C
@Nonnull
- private final Map<Class<?>, Class<? extends ObjectWatcher<?>>> watchers =
- new HashMap<Class<?>, Class<? extends ObjectWatcher<?>>>();
+ private final Map<Class<?>, List<Class<? extends ObjectWatcher<?>>>> watchers =
+ new HashMap<Class<?>, List<Class<? extends ObjectWatcher<?>>>>();
+ // Set of classes not watched (speedup non watched classes)
@Nonnull
private final Set<Class<?>> notWatched = new HashSet<Class<?>>();
@Nonnull
- private final Object watcherLock = new Object();
+ private final ReentrantReadWriteLock watcherLock = new ReentrantReadWriteLock();
@Override
- public synchronized <T> void registerWatcher(@Nonnull Class<T> objectClass,
+ public synchronized <T> void registerWatcher(@Nonnull Class<T> rootWatchedClass,
@Nonnull Class<? extends ObjectWatcher<? extends T>> watcherClass) {
WeakHashMap<Object, ObjectWatcher<Object>> map =
new WeakHashMap<Object, ObjectWatcher<Object>>();
- synchronized (watcherLock) {
+ watcherLock.writeLock().lock();
+ try {
objects.put(watcherClass, map);
- watchers.put(objectClass, watcherClass);
- for (Class<?> cls : notWatched) {
- if (objectClass.isAssignableFrom(cls)) {
+ List<Class<? extends ObjectWatcher<?>>> list = watchers.get(rootWatchedClass);
+ if (list == null) {
+ list = new ArrayList<Class<? extends ObjectWatcher<?>>>(1);
+ watchers.put(rootWatchedClass, list);
+ }
+
+ list.add(watcherClass);
+
+ Iterator<Class<?>> iterNotWatched = notWatched.iterator();
+ while (iterNotWatched.hasNext()) {
+ Class<?> watchedClass = iterNotWatched.next();
+ if (rootWatchedClass.isAssignableFrom(watchedClass)) {
logger.log(Level.INFO, "Watcher ''{0}'' missed some instances of type ''{1}''",
- new Object[] {watcherClass.getName(), cls.getName()});
+ new Object[] {watcherClass.getName(), watchedClass.getName()});
- watchers.put(cls, watcherClass);
- notWatched.remove(objectClass);
+ list = watchers.get(watchedClass);
+ if (list == null) {
+ list = new ArrayList<Class<? extends ObjectWatcher<?>>>(1);
+ watchers.put(watchedClass, list);
+ }
+
+ list.add(watcherClass);
+ iterNotWatched.remove();
}
}
+ } finally {
+ watcherLock.writeLock().unlock();
}
}
@Override
public void registerObject(@Nonnull Object object, @Nonnegative long size, int count) {
- Class<? extends ObjectWatcher<?>> watcherClass = null;
+ enable.set(Boolean.FALSE);
+ Class<?> objectClass = object.getClass();
+ List<Class<? extends ObjectWatcher<?>>> list = null;
- synchronized (watcherLock) {
- if (notWatched.contains(object.getClass())) {
+ watcherLock.readLock().lock();
+ try {
+ // If this object is not watched explicitly, go away
+ if (notWatched.contains(objectClass)) {
return;
}
- watcherClass = watchers.get(object.getClass());
- if (watcherClass == null) {
- for (Entry<Class<?>, Class<? extends ObjectWatcher<?>>> entry : watchers.entrySet()) {
- if (entry.getKey().isAssignableFrom(object.getClass())) {
- watcherClass = entry.getValue();
- break;
+ list = watchers.get(objectClass);
+ } finally {
+ watcherLock.readLock().unlock();
+ }
+
+ if (list == null) {
+ watcherLock.writeLock().lock();
+ try {
+ list = watchers.get(objectClass);
+ if (list == null) {
+ list = new ArrayList<Class<? extends ObjectWatcher<?>>>(1);
+
+ for (Entry<Class<?>, List<Class<? extends ObjectWatcher<?>>>> entry :
+ watchers.entrySet()) {
+ if (entry.getKey().isAssignableFrom(objectClass)) {
+ list.addAll(entry.getValue());
+ }
}
}
- if (watcherClass != null) {
- watchers.put(object.getClass(), watcherClass);
+ if (!list.isEmpty()) {
+ watchers.put(objectClass, list);
} else {
- notWatched.add(object.getClass());
- return;
+ notWatched.add(objectClass);
}
+ } finally {
+ watcherLock.writeLock().unlock();
}
}
- try {
- @SuppressWarnings("unchecked")
- ObjectWatcher<Object> watcher = (ObjectWatcher<Object>) watcherClass.newInstance();
- WeakHashMap<Object, ObjectWatcher<Object>> weak = objects.get(watcherClass);
- assert weak != null; // If watchers contains object.getClass, then objects contains it also,
- // see registerWatcher
- if (watcher.notifyInstantiation(object, size, count, getCurrentEventType())) {
- weak.put(object, watcher);
+ for (Class<? extends ObjectWatcher<?>> watcherClass : list) {
+ try {
+ @SuppressWarnings("unchecked")
+ ObjectWatcher<Object> watcher = (ObjectWatcher<Object>) watcherClass.newInstance();
+
+ if (watcher.notifyInstantiation(object, size, count, getCurrentEventType())) {
+ WeakHashMap<Object, ObjectWatcher<Object>> weak = objects.get(watcherClass);
+ assert weak != null; // If watchers contains object.getClass, then objects contains it
+ // also, see registerWatcher
+ weak.put(object, watcher);
+ }
+ } catch (InstantiationException e) {
+ logger.log(Level.WARNING, "Can not instantiate Watcher", e);
+ } catch (IllegalAccessException e) {
+ logger.log(Level.WARNING, "Can not instantiate Watcher", e);
}
- } catch (InstantiationException e) {
- logger.log(Level.WARNING, "Can not instantiate Watcher", e);
- } catch (IllegalAccessException e) {
- logger.log(Level.WARNING, "Can not instantiate Watcher", e);
}
}
}
diff --git a/sched/src/com/android/sched/util/log/stats/Alloc.java b/sched/src/com/android/sched/util/log/stats/Alloc.java
index 2bf2989..ae1b50b 100644
--- a/sched/src/com/android/sched/util/log/stats/Alloc.java
+++ b/sched/src/com/android/sched/util/log/stats/Alloc.java
@@ -46,53 +46,10 @@ public class Alloc extends Statistic {
@Override
@Nonnull
- @Deprecated
- public Object getValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getHumanReadableValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getDescription(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "Count";
- case 1:
- return "Size";
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getType(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "number";
- case 1:
- return "number";
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
public String getDescription() {
return "Allocation";
}
-
@Nonnull
private static final String[] HEADER = new String[] {
"Count",
diff --git a/sched/src/com/android/sched/util/log/stats/AllocImpl.java b/sched/src/com/android/sched/util/log/stats/AllocImpl.java
index bbed19c..df2b01a 100644
--- a/sched/src/com/android/sched/util/log/stats/AllocImpl.java
+++ b/sched/src/com/android/sched/util/log/stats/AllocImpl.java
@@ -18,7 +18,6 @@ package com.android.sched.util.log.stats;
import com.google.common.collect.Iterators;
-import com.android.sched.util.log.tracer.probe.MemoryBytesProbe;
import com.android.sched.util.table.DataHeader;
import com.android.sched.util.table.DataRow;
@@ -63,34 +62,6 @@ public class AllocImpl extends Alloc implements DataRow, DataHeader {
@Override
@Nonnull
- @Deprecated
- public synchronized Object getValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Long.valueOf(number);
- case 1:
- return Long.valueOf(size);
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
- @Deprecated
- public synchronized String getHumanReadableValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Long.toString(number);
- case 1:
- return MemoryBytesProbe.formatBytes(size);
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
public synchronized Iterator<Object> iterator() {
return Iterators.<Object> forArray(
Long.valueOf(number),
diff --git a/sched/src/com/android/sched/util/log/stats/ArrayAlloc.java b/sched/src/com/android/sched/util/log/stats/ArrayAlloc.java
index 5b29bbf..d086b49 100644
--- a/sched/src/com/android/sched/util/log/stats/ArrayAlloc.java
+++ b/sched/src/com/android/sched/util/log/stats/ArrayAlloc.java
@@ -18,9 +18,9 @@ package com.android.sched.util.log.stats;
import com.google.common.collect.ObjectArrays;
+import com.android.sched.util.codec.ByteFormatter;
import com.android.sched.util.codec.Formatter;
import com.android.sched.util.codec.LongCodec;
-import com.android.sched.util.codec.ByteFormatter;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
@@ -49,64 +49,6 @@ public class ArrayAlloc extends Statistic {
@Override
@Nonnull
- @Deprecated
- public Object getValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getHumanReadableValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getDescription(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "Array count";
- case 1:
- return "Total size";
- case 2:
- return "Total elements";
- case 3:
- return "Min elements";
- case 4:
- return "Average elements";
- case 5:
- return "max elements";
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getType(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "number";
- case 1:
- return "number";
- case 2:
- return "number";
- case 3:
- return "number";
- case 4:
- return "number";
- case 5:
- return "number";
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
public String getDescription() {
return "Array allocation";
}
diff --git a/sched/src/com/android/sched/util/log/stats/ArrayAllocImpl.java b/sched/src/com/android/sched/util/log/stats/ArrayAllocImpl.java
index ff59b55..f5b5c5e 100644
--- a/sched/src/com/android/sched/util/log/stats/ArrayAllocImpl.java
+++ b/sched/src/com/android/sched/util/log/stats/ArrayAllocImpl.java
@@ -18,7 +18,6 @@ package com.android.sched.util.log.stats;
import com.google.common.collect.Iterators;
-import com.android.sched.util.log.tracer.probe.MemoryBytesProbe;
import com.android.sched.util.table.DataRow;
import java.util.Iterator;
@@ -69,34 +68,6 @@ public class ArrayAllocImpl extends ArrayAlloc implements DataRow {
@Override
@Nonnull
- @Deprecated
- public synchronized Object getValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Long.valueOf(number);
- case 1:
- return Long.valueOf(size);
- default:
- return element.getValue(columnIdx - 1);
- }
- }
-
- @Override
- @Nonnull
- @Deprecated
- public synchronized String getHumanReadableValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Long.toString(number);
- case 1:
- return MemoryBytesProbe.formatBytes(size);
- default:
- return element.getHumanReadableValue(columnIdx - 1);
- }
- }
-
- @Override
- @Nonnull
public synchronized Iterator<Object> iterator() {
return Iterators.concat(
Iterators.forArray(Long.valueOf(number), Long.valueOf(size)), element.iterator());
diff --git a/sched/src/com/android/sched/util/log/stats/Counter.java b/sched/src/com/android/sched/util/log/stats/Counter.java
index 8001004..fb6b630 100644
--- a/sched/src/com/android/sched/util/log/stats/Counter.java
+++ b/sched/src/com/android/sched/util/log/stats/Counter.java
@@ -24,7 +24,7 @@ import javax.annotation.Nonnull;
/**
- * Represents a counter statistic when statistic is not enabled..
+ * Represents a counter statistic when statistic is not enabled.
*/
public class Counter extends Statistic {
protected Counter(@Nonnull StatisticId<? extends Statistic> id) {
@@ -60,45 +60,6 @@ public class Counter extends Statistic {
@Override
@Nonnull
- @Deprecated
- public Object getValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getHumanReadableValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getDescription(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "Number";
- default:
- throw new AssertionError();
- }
- }
-
-
- @Override
- @Nonnull
- @Deprecated
- public String getType(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "number";
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
public String getDescription() {
return "Counter";
}
diff --git a/sched/src/com/android/sched/util/log/stats/CounterImpl.java b/sched/src/com/android/sched/util/log/stats/CounterImpl.java
index 32aca6c..3aeca0a 100644
--- a/sched/src/com/android/sched/util/log/stats/CounterImpl.java
+++ b/sched/src/com/android/sched/util/log/stats/CounterImpl.java
@@ -22,7 +22,6 @@ import com.android.sched.util.table.DataRow;
import java.util.Iterator;
-import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
@@ -82,24 +81,6 @@ public class CounterImpl extends Counter implements DataRow {
@Override
@Nonnull
- @Deprecated
- public Object getValue(@Nonnegative int columnIdx) {
- assert columnIdx == 0;
-
- return Long.valueOf(value);
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getHumanReadableValue(@Nonnegative int columnIdx) {
- assert columnIdx == 0;
-
- return Long.valueOf(value).toString();
- }
-
- @Override
- @Nonnull
public synchronized Iterator<Object> iterator() {
return Iterators.<Object> forArray(Long.valueOf(value));
}
diff --git a/sched/src/com/android/sched/util/log/stats/ExtendedSample.java b/sched/src/com/android/sched/util/log/stats/ExtendedSample.java
new file mode 100644
index 0000000..5ade77f
--- /dev/null
+++ b/sched/src/com/android/sched/util/log/stats/ExtendedSample.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.util.log.stats;
+
+import com.android.sched.util.codec.DoubleCodec;
+import com.android.sched.util.codec.Formatter;
+import com.android.sched.util.codec.LongCodec;
+
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+
+/**
+ * Extended statistic computation on a set of values when statistic is not enabled. Have Median,
+ * First quartile, Third quartile.
+ */
+public class ExtendedSample extends Statistic {
+ protected ExtendedSample(@Nonnull StatisticId<? extends Statistic> id) {
+ super(id);
+ }
+
+ public void add(double value) {
+ }
+
+ @Nonnegative
+ public int getCount() {
+ return 0;
+ }
+
+ public double getTotal() {
+ return 0;
+ }
+
+ public double getMin() {
+ return Double.NaN;
+ }
+
+ public double getAverage() {
+ return Double.NaN;
+ }
+
+ public double getMax() {
+ return Double.NaN;
+ }
+
+ public double getFirstQuartile() {
+ return Double.NaN;
+ }
+
+ public double getMedian() {
+ return Double.NaN;
+ }
+
+ public double getThirdQuartile() {
+ return Double.NaN;
+ }
+
+ @Override
+ public void merge(@Nonnull Statistic statistic) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ @Nonnull
+ public String getDescription() {
+ return "Sample";
+ }
+
+
+ @Nonnull
+ private static final String[] HEADER = new String[] {
+ "Count",
+ "Total",
+ "Min",
+ "Average",
+ "First Quartile",
+ "Median",
+ "Third Quartile",
+ "Max"
+ };
+
+ @Override
+ @Nonnull
+ public String[] getHeader() {
+ return HEADER.clone();
+ }
+
+ @Nonnull
+ public static String[] getStaticHeader() {
+ return HEADER.clone();
+ }
+
+ @Nonnull
+ public static Formatter<? extends Object>[] getStaticFormatters() {
+ return new Formatter<?>[] {
+ new LongCodec(),
+ new DoubleCodec(),
+ new DoubleCodec(),
+ new DoubleCodec(),
+ new DoubleCodec(),
+ new DoubleCodec(),
+ new DoubleCodec(),
+ new DoubleCodec()
+ };
+ }
+
+ @Override
+ @Nonnull
+ public Formatter<? extends Object>[] getFormatters() {
+ return getStaticFormatters();
+ }
+
+ @Override
+ @Nonnegative
+ public int getColumnCount() {
+ return HEADER.length;
+ }
+}
diff --git a/sched/src/com/android/sched/util/log/stats/ExtendedSampleImpl.java b/sched/src/com/android/sched/util/log/stats/ExtendedSampleImpl.java
new file mode 100644
index 0000000..c0e77c4
--- /dev/null
+++ b/sched/src/com/android/sched/util/log/stats/ExtendedSampleImpl.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.util.log.stats;
+
+import com.google.common.collect.Iterators;
+
+import com.android.sched.util.table.DataHeader;
+import com.android.sched.util.table.DataRow;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+
+/**
+ * Extended statistic computation on a set of values. Have Median, First quartile, Third quartile.
+ */
+public class ExtendedSampleImpl extends ExtendedSample implements DataRow, DataHeader {
+ private static final int INITIAL_CAPACITY = 16;
+ private static final int INCREMENT = 0;
+
+ @Nonnull
+ protected double[] samples = new double[INITIAL_CAPACITY];
+ @Nonnegative
+ protected int count = 0;
+ private double total;
+ private boolean isSorted = true;
+
+ @Nonnegative
+ private final int increment;
+
+ public ExtendedSampleImpl(@Nonnull StatisticId<? extends Statistic> id) {
+ super(id);
+
+ this.increment = INCREMENT;
+ }
+
+ @Override
+ public synchronized void add(double value) {
+ ensureCapacity(count);
+
+ samples[count++] = value;
+ total += value;
+ isSorted = false;
+ }
+
+ @Override
+ @Nonnegative
+ public int getCount() {
+ return count;
+ }
+
+ @Override
+ public double getTotal() {
+ return total;
+ }
+
+ @Override
+ public synchronized double getMin() {
+ ensureSorted();
+ return samples[0];
+ }
+
+ @Override
+ public synchronized double getAverage() {
+ return total / count;
+ }
+
+ @Override
+ public synchronized double getMax() {
+ ensureSorted();
+ return samples[count];
+ }
+
+ @Override
+ public synchronized double getFirstQuartile() {
+ return getNth(1, 4);
+ }
+
+ @Override
+ public synchronized double getMedian() {
+ return getNth(1, 2);
+ }
+
+ @Override
+ public synchronized double getThirdQuartile() {
+ return getNth(3, 4);
+ }
+
+ @Override
+ public synchronized void merge(@Nonnull Statistic statistic) {
+ ExtendedSampleImpl samples = (ExtendedSampleImpl) statistic;
+
+ synchronized (samples) {
+ ensureCapacity(count + samples.count);
+
+ System.arraycopy(samples.samples, 0, this.samples, count, samples.count);
+ count += samples.count;
+ total += samples.total;
+ isSorted = false;
+ }
+ }
+
+ private void ensureSorted() {
+ if (!isSorted) {
+ Arrays.sort(samples, 0, count);
+ isSorted = true;
+ }
+ }
+
+ private void ensureCapacity (@Nonnegative int index) {
+ if (index >= samples.length) {
+ int newLength;
+
+ if (increment <= 0) {
+ newLength = samples.length * 2 + 1;
+ } else {
+ newLength = samples.length + increment;
+ }
+
+ double[] newArray = new double[newLength];
+ System.arraycopy(samples, 0, newArray, 0, count);
+
+ samples = newArray;
+ }
+ }
+
+ private double getNth(int n, int d) {
+ ensureSorted();
+
+ if (count == 0) {
+ return Double.NaN;
+ }
+
+ if (count == 1) {
+ return samples[0];
+ }
+
+ double pos = (double) (n * (count + 1)) / (double) d;
+
+ if (pos < 1.0) {
+ return samples[0];
+ }
+
+ double floor = Math.floor(pos);
+ double diff = pos - floor;
+ double vLow = samples[(int) pos - 1];
+
+ if (diff == 0) {
+ return vLow;
+ } else {
+ double vHigh = samples[(int) pos];
+ return vLow + diff * (vHigh - vLow);
+ }
+ }
+
+ @Override
+ @Nonnull
+ public synchronized Iterator<Object> iterator() {
+ ensureSorted();
+
+ return Iterators.<Object>forArray(
+ Long.valueOf(getCount()),
+ Double.valueOf(getTotal()),
+ Double.valueOf(getMin()),
+ Double.valueOf(getAverage()),
+ Double.valueOf(getFirstQuartile()),
+ Double.valueOf(getMedian()),
+ Double.valueOf(getThirdQuartile()),
+ Double.valueOf(getMax()));
+ }
+}
diff --git a/sched/src/com/android/sched/util/log/stats/ObjectAlloc.java b/sched/src/com/android/sched/util/log/stats/ObjectAlloc.java
index ed57ae4..eb547a2 100644
--- a/sched/src/com/android/sched/util/log/stats/ObjectAlloc.java
+++ b/sched/src/com/android/sched/util/log/stats/ObjectAlloc.java
@@ -46,52 +46,6 @@ public class ObjectAlloc extends Statistic {
@Override
@Nonnull
- @Deprecated
- public Object getValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getHumanReadableValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getDescription(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "Object count";
- case 1:
- return "Object size";
- case 2:
- return "Total size";
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
- @Deprecated
- public String getType(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "number";
- case 1:
- return "number";
- case 2:
- return "number";
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
public String getDescription() {
return "Object allocation";
}
diff --git a/sched/src/com/android/sched/util/log/stats/ObjectAllocImpl.java b/sched/src/com/android/sched/util/log/stats/ObjectAllocImpl.java
index 3f511d4..eb0f887 100644
--- a/sched/src/com/android/sched/util/log/stats/ObjectAllocImpl.java
+++ b/sched/src/com/android/sched/util/log/stats/ObjectAllocImpl.java
@@ -18,7 +18,6 @@ package com.android.sched.util.log.stats;
import com.google.common.collect.Iterators;
-import com.android.sched.util.log.tracer.probe.MemoryBytesProbe;
import com.android.sched.util.table.DataHeader;
import com.android.sched.util.table.DataRow;
@@ -71,38 +70,6 @@ public class ObjectAllocImpl extends ObjectAlloc implements DataRow, DataHeader
@Override
@Nonnull
- @Deprecated
- public synchronized Object getValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Long.valueOf(number);
- case 1:
- return Long.valueOf(size);
- case 2:
- return Long.valueOf(size * number);
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
- @Deprecated
- public synchronized String getHumanReadableValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Long.toString(number);
- case 1:
- return MemoryBytesProbe.formatBytes(size);
- case 2:
- return MemoryBytesProbe.formatBytes(size * number);
- default:
- throw new AssertionError();
- }
- }
-
- @Override
- @Nonnull
public synchronized Iterator<Object> iterator() {
return Iterators.<Object> forArray(
Long.valueOf(number),
diff --git a/sched/src/com/android/sched/util/log/stats/Percent.java b/sched/src/com/android/sched/util/log/stats/Percent.java
index 86096c7..f36cd47 100644
--- a/sched/src/com/android/sched/util/log/stats/Percent.java
+++ b/sched/src/com/android/sched/util/log/stats/Percent.java
@@ -40,58 +40,21 @@ public class Percent extends Statistic {
public void add(boolean value) {
}
- public double getPercent() {
- return Double.NaN;
- }
-
- @Override
- public void merge(@Nonnull Statistic statistic) {
+ public void removeTrue() {
}
- @Override
- @Nonnull
- @Deprecated
- public Object getValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
+ public void removeFalse() {
}
- @Override
- @Nonnull
- @Deprecated
- public String getHumanReadableValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
+ public void remove(boolean value) {
}
- @Override
- @Nonnull
- @Deprecated
- public String getDescription(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "Percent";
- case 1:
- return "Number";
- case 2:
- return "Total";
- default:
- throw new AssertionError();
- }
+ public double getPercent() {
+ return Double.NaN;
}
@Override
- @Nonnull
- @Deprecated
- public String getType(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "number";
- case 1:
- return "number";
- case 2:
- return "number";
- default:
- throw new AssertionError();
- }
+ public void merge(@Nonnull Statistic statistic) {
}
@Override
diff --git a/sched/src/com/android/sched/util/log/stats/PercentImpl.java b/sched/src/com/android/sched/util/log/stats/PercentImpl.java
index 7f02617..99f3916 100644
--- a/sched/src/com/android/sched/util/log/stats/PercentImpl.java
+++ b/sched/src/com/android/sched/util/log/stats/PercentImpl.java
@@ -20,10 +20,8 @@ import com.google.common.collect.Iterators;
import com.android.sched.util.table.DataRow;
-import java.text.NumberFormat;
import java.util.Iterator;
-import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
@@ -59,66 +57,42 @@ public class PercentImpl extends Percent implements DataRow {
}
@Override
- public synchronized double getPercent() {
- return (double ) numTrue / (double) total;
+ public synchronized void removeTrue() {
+ this.numTrue--;
+ this.total--;
}
@Override
- public synchronized void merge(@Nonnull Statistic statistic) {
- PercentImpl percent = (PercentImpl) statistic;
-
- synchronized (percent) {
- this.numTrue += percent.numTrue;
- this.total += percent.total;
- }
+ public synchronized void removeFalse() {
+ this.total--;
}
@Override
- @Nonnull
- @Deprecated
- public synchronized Object getValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Double.valueOf((double ) numTrue / (double) total);
- case 1:
- return Long.valueOf(numTrue);
- case 2:
- return Long.valueOf(total);
- default:
- throw new AssertionError();
+ public synchronized void remove(boolean value) {
+ if (value) {
+ removeTrue();
+ } else {
+ removeFalse();
}
}
@Override
- @Nonnull
- @Deprecated
- public synchronized String getHumanReadableValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- if (total == 0) {
- return notANumber;
- } else {
- return formatter.format((double) numTrue / (double) total);
- }
- case 1:
- return Long.toString(numTrue);
- case 2:
- return Long.toString(total);
- default:
- throw new AssertionError();
+ public synchronized double getPercent() {
+ if (numTrue < 0 || total < 0) {
+ return Double.NaN;
}
+
+ return (double ) numTrue / (double) total;
}
- @Nonnull
- @Deprecated
- private static NumberFormat formatter = NumberFormat.getPercentInstance();
- @Nonnull
- @Deprecated
- private static String notANumber;
+ @Override
+ public synchronized void merge(@Nonnull Statistic statistic) {
+ PercentImpl percent = (PercentImpl) statistic;
- static {
- formatter.setMinimumFractionDigits(2);
- notANumber = formatter.format(0).replace('0', '-');
+ synchronized (percent) {
+ this.numTrue += percent.numTrue;
+ this.total += percent.total;
+ }
}
@Nonnull
diff --git a/sched/src/com/android/sched/util/log/stats/Sample.java b/sched/src/com/android/sched/util/log/stats/Sample.java
index 027074b..115fb03 100644
--- a/sched/src/com/android/sched/util/log/stats/Sample.java
+++ b/sched/src/com/android/sched/util/log/stats/Sample.java
@@ -26,7 +26,7 @@ import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
/**
- * Simple statistic computation on a set of values.
+ * Simple statistic computation on a set of values when statistic is not enabled.
*/
public class Sample extends Statistic {
protected Sample(@Nonnull StatisticId<? extends Statistic> id) {
@@ -41,66 +41,36 @@ public class Sample extends Statistic {
throw new AssertionError();
}
- @Override
- @Nonnull
- @Deprecated
- public Object getValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
+ @Nonnegative
+ public int getCount() {
+ return 0;
}
- @Override
- @Nonnull
- @Deprecated
- public String getHumanReadableValue(@Nonnegative int columnIdx) {
- throw new AssertionError();
+ public double getTotal() {
+ return 0;
}
- @Override
- @Nonnull
- @Deprecated
- public String getDescription(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "Count";
- case 1:
- return "Total";
- case 2:
- return "Min";
- case 3:
- return "Average";
- case 4:
- return "Max";
- case 5:
- return "Min Marker";
- case 6:
- return "Max Marker";
- default:
- throw new AssertionError();
- }
+ public double getMin() {
+ return Double.NaN;
}
- @Override
- @Nonnull
- @Deprecated
- public String getType(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return "number";
- case 1:
- return "number";
- case 2:
- return "number";
- case 3:
- return "number";
- case 4:
- return "number";
- case 5:
- return "string";
- case 6:
- return "string";
- default:
- throw new AssertionError();
- }
+ public double getAverage() {
+ return Double.NaN;
+ }
+
+ public double getMax() {
+ return Double.NaN;
+ }
+
+ @CheckForNull
+ public Object getMinObject() {
+ return null;
+
+ }
+
+ @CheckForNull
+ public Object getMaxObject() {
+ return null;
}
@Override
@@ -110,7 +80,7 @@ public class Sample extends Statistic {
}
- @Nonnegative
+ @Nonnull
private static final String[] HEADER = new String[] {
"Count",
"Total",
diff --git a/sched/src/com/android/sched/util/log/stats/SampleImpl.java b/sched/src/com/android/sched/util/log/stats/SampleImpl.java
index 3a51c1a..50d609b 100644
--- a/sched/src/com/android/sched/util/log/stats/SampleImpl.java
+++ b/sched/src/com/android/sched/util/log/stats/SampleImpl.java
@@ -31,7 +31,8 @@ import javax.annotation.Nonnull;
* Simple statistic computation on a set of values.
*/
public class SampleImpl extends Sample implements DataRow, DataHeader {
- private long count;
+ @Nonnegative
+ private int count;
private double min = Double.POSITIVE_INFINITY;
@CheckForNull
@@ -64,6 +65,46 @@ public class SampleImpl extends Sample implements DataRow, DataHeader {
count++;
}
+
+ @Override
+ @Nonnegative
+ public int getCount() {
+ return count;
+ }
+
+ @Override
+ public double getTotal() {
+ return total;
+ }
+
+ @Override
+ public double getMin() {
+ return min;
+ }
+
+ @Override
+ public synchronized double getAverage() {
+ return total / count;
+ }
+
+ @Override
+ public double getMax() {
+ return max;
+ }
+
+ @Override
+ @CheckForNull
+ public Object getMinObject() {
+ return minObject;
+
+ }
+
+ @Override
+ @CheckForNull
+ public Object getMaxObject() {
+ return maxObject;
+ }
+
@Override
public synchronized void merge(@Nonnull Statistic statistic) {
SampleImpl samples = (SampleImpl) statistic;
@@ -82,94 +123,14 @@ public class SampleImpl extends Sample implements DataRow, DataHeader {
@Nonnull
@Override
- @Deprecated
- public Object getValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Long.valueOf(count);
- case 1:
- return Double.valueOf(total);
- case 2:
- if (min == Double.POSITIVE_INFINITY) {
- return Double.valueOf(Double.MAX_VALUE);
- } else {
- return Double.valueOf(min);
- }
- case 3:
- if (count == 0) {
- return Long.valueOf(0);
- } else {
- return Double.valueOf(total / count);
- }
- case 4:
- if (max == Double.NEGATIVE_INFINITY) {
- return Double.valueOf(Double.MIN_VALUE);
- } else {
- return Double.valueOf(max);
- }
- case 5:
- return "";
- case 6:
- return "";
- default:
- throw new AssertionError();
- }
- }
-
- @Nonnull
- @Override
- @Deprecated
- public String getHumanReadableValue(@Nonnegative int columnIdx) {
- switch (columnIdx) {
- case 0:
- return Long.toString(count);
- case 1:
- return Double.toString(total);
- case 2:
- if (min == Double.POSITIVE_INFINITY) {
- return "--";
- } else {
- return Double.toString(min);
- }
- case 3:
- if (count == 0) {
- return "--";
- } else {
- return Double.toString(total / count);
- }
- case 4:
- if (max == Double.NEGATIVE_INFINITY) {
- return "--";
- } else {
- return Double.toString(max);
- }
- case 5:
- if (minObject == null) {
- return "--";
- } else {
- return minObject.toString();
- }
- case 6:
- if (maxObject == null) {
- return "--";
- } else {
- return maxObject.toString();
- }
- default:
- throw new AssertionError();
- }
- }
-
- @Nonnull
- @Override
- public Iterator<Object> iterator() {
+ public synchronized Iterator<Object> iterator() {
return Iterators.forArray(
- Long.valueOf(count),
- Double.valueOf(total),
- Double.valueOf(min),
- Double.valueOf(total / count),
- Double.valueOf(max),
- minObject,
- maxObject);
+ Integer.valueOf(getCount()),
+ Double.valueOf(getTotal()),
+ Double.valueOf(getMin()),
+ Double.valueOf(getAverage()),
+ Double.valueOf(getMax()),
+ getMinObject(),
+ getMaxObject());
}
}
diff --git a/sched/src/com/android/sched/util/log/stats/Statistic.java b/sched/src/com/android/sched/util/log/stats/Statistic.java
index 569d85c..93d2535 100644
--- a/sched/src/com/android/sched/util/log/stats/Statistic.java
+++ b/sched/src/com/android/sched/util/log/stats/Statistic.java
@@ -16,7 +16,12 @@
package com.android.sched.util.log.stats;
+import com.google.common.collect.Iterators;
+
+import com.android.sched.util.codec.Formatter;
+import com.android.sched.util.codec.ToStringFormatter;
import com.android.sched.util.table.DataHeader;
+import com.android.sched.util.table.DataRow;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
@@ -40,27 +45,50 @@ public abstract class Statistic implements DataHeader {
}
@Nonnull
- @Deprecated
- public abstract Object getValue(@Nonnegative int columnIdx);
+ public abstract String getDescription();
+ @Override
@Nonnull
- @Deprecated
- public abstract String getHumanReadableValue(@Nonnegative int columnIdx);
+ public String toString() {
+ return id.getName();
+ }
+
+ //
+ // Adapter for deprecated API
+ //
@Nonnull
@Deprecated
- public abstract String getDescription(@Nonnegative int columnIdx);
+ public final String getDescription(int columnIdx) {
+ return getHeader()[columnIdx];
+ }
@Nonnull
@Deprecated
- public abstract String getType(@Nonnegative int columnIdx);
+ public final String getType(int columnIdx) {
+ if (getFormatters()[columnIdx] instanceof ToStringFormatter) {
+ return "string";
+ } else {
+ return "number";
+ }
+ }
@Nonnull
- public abstract String getDescription();
+ @Deprecated
+ public final Object getValue(@Nonnegative int columnIdx) {
+ if (this instanceof DataRow) {
+ DataRow data = (DataRow) this;
- @Override
+ return Iterators.get(data.iterator(), columnIdx);
+ }
+
+ throw new AssertionError();
+ }
+
+ @SuppressWarnings("unchecked")
@Nonnull
- public String toString() {
- return id.getName();
+ @Deprecated
+ public final String getHumanReadableValue(@Nonnegative int columnIdx) {
+ return ((Formatter<Object>) (getFormatters()[columnIdx])).formatValue(getValue(columnIdx));
}
}
diff --git a/sched/src/com/android/sched/util/log/stats/StatisticId.java b/sched/src/com/android/sched/util/log/stats/StatisticId.java
index c6f0fe5..597a5a3 100644
--- a/sched/src/com/android/sched/util/log/stats/StatisticId.java
+++ b/sched/src/com/android/sched/util/log/stats/StatisticId.java
@@ -18,12 +18,8 @@ package com.android.sched.util.log.stats;
import com.android.sched.util.config.ReflectFactory;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Nonnull;
@@ -35,9 +31,6 @@ import javax.annotation.Nonnull;
*/
public class StatisticId<T extends Statistic> {
@Nonnull
- private static Set<StatisticId<? extends Statistic>> ids =
- Collections.synchronizedSet(new HashSet<StatisticId<? extends Statistic>>());
- @Nonnull
private static Map<Class<? extends Statistic>, Statistic> dummies =
new ConcurrentHashMap<Class<? extends Statistic>, Statistic>();
@Nonnull
@@ -70,8 +63,6 @@ public class StatisticId<T extends Statistic> {
dummies.put(dummyClass, newDummyInstance());
regulars.put(dummyClass, regularClass);
}
-
- ids.add(this);
}
@Nonnull
@@ -96,12 +87,6 @@ public class StatisticId<T extends Statistic> {
@Nonnull
@Deprecated
- public static synchronized Collection<StatisticId<? extends Statistic>> getIds() {
- return new ArrayList<StatisticId<? extends Statistic>>(ids);
- }
-
- @Nonnull
- @Deprecated
public static synchronized Collection<? extends Statistic> getDummies() {
return dummies.values();
}
diff --git a/sched/src/com/android/sched/util/log/tracer/DynamicEventType.java b/sched/src/com/android/sched/util/log/tracer/DynamicEventType.java
index 2f2ca1b..c9f43ca 100644
--- a/sched/src/com/android/sched/util/log/tracer/DynamicEventType.java
+++ b/sched/src/com/android/sched/util/log/tracer/DynamicEventType.java
@@ -16,7 +16,6 @@
package com.android.sched.util.log.tracer;
-import com.android.sched.util.Colors;
import com.android.sched.util.log.EventType;
import javax.annotation.Nonnull;
@@ -26,19 +25,10 @@ import javax.annotation.Nonnull;
*/
class DynamicEventType implements EventType {
@Nonnull
- private final String cssColor;
- @Nonnull
private final String name;
DynamicEventType(@Nonnull String name) {
this.name = name;
- this.cssColor = Colors.getCssColor(Colors.getRandomPastel(name.hashCode()));
- }
-
- @Override
- @Nonnull
- public String getColor() {
- return cssColor;
}
@Override
diff --git a/sched/src/com/android/sched/util/log/tracer/TracerEventType.java b/sched/src/com/android/sched/util/log/tracer/TracerEventType.java
index 59d825d..3558a45 100644
--- a/sched/src/com/android/sched/util/log/tracer/TracerEventType.java
+++ b/sched/src/com/android/sched/util/log/tracer/TracerEventType.java
@@ -24,24 +24,16 @@ import javax.annotation.Nonnull;
* Represents a type of event whose performance is tracked.
*/
public enum TracerEventType implements EventType {
- OVERHEAD("Tracer overhead", "Plum"),
- NOEVENT("No Event", "Black"),
- NOTYPE("Not a Type", "Black");
+ OVERHEAD("Tracer overhead"),
+ NOEVENT("No Event"),
+ SINGLETON("Singleton event"),
+ NOTYPE("Not a Type");
@Nonnull
- private final String cssColor;
- @Nonnull
private final String name;
- TracerEventType(@Nonnull String name, @Nonnull String cssColor) {
+ TracerEventType(@Nonnull String name) {
this.name = name;
- this.cssColor = cssColor;
- }
-
- @Override
- @Nonnull
- public String getColor() {
- return cssColor;
}
@Override
diff --git a/sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java b/sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java
index 09a8e18..78fd9b8 100644
--- a/sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java
+++ b/sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java
@@ -22,23 +22,17 @@ import com.android.sched.util.log.Tracer;
import com.android.sched.util.log.TracerFactory;
import com.android.sched.util.log.stats.Alloc;
import com.android.sched.util.log.stats.AllocImpl;
-import com.android.sched.util.log.stats.ArrayAlloc;
-import com.android.sched.util.log.stats.ArrayAllocImpl;
-import com.android.sched.util.log.stats.ObjectAlloc;
-import com.android.sched.util.log.stats.ObjectAllocImpl;
import com.android.sched.util.log.stats.Statistic;
import com.android.sched.util.log.stats.StatisticId;
import java.util.Iterator;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
/**
- * Class to watch {@link Object} creation.
+ * Class to watch {@link Object} creation and make a global statistic about allocation.
*/
public class AllocationWatcher implements ObjectWatcher<Object> {
static class Statistics implements ObjectWatcher.Statistics {
@@ -54,14 +48,6 @@ public class AllocationWatcher implements ObjectWatcher<Object> {
"Total object and array allocations",
AllocImpl.class, Alloc.class);
- @Nonnull
- private static final Map<Class<?>, StatisticId<ObjectAlloc>> objectStats =
- new ConcurrentHashMap<Class<?>, StatisticId<ObjectAlloc>>();
-
- @Nonnull
- private static final Map<Class<?>, StatisticId<ArrayAlloc>> arrayStats =
- new ConcurrentHashMap<Class<?>, StatisticId<ArrayAlloc>>();
-
@Override
public boolean notifyInstantiation(
@Nonnull Object object, @Nonnegative long size, int count, @Nonnull EventType notUsed) {
@@ -77,46 +63,19 @@ public class AllocationWatcher implements ObjectWatcher<Object> {
}
private void notifyObject(@Nonnull Class<?> type, @Nonnegative long size) {
- synchronized (AllocationWatcher.class) {
- StatisticId<ObjectAlloc> id = objectStats.get(type);
- if (id == null) {
- String name = type.getName();
-
- id = new StatisticId<ObjectAlloc>("jack.allocation.object." + name,
- "Object allocation of type " + type.getName(), ObjectAllocImpl.class,
- ObjectAlloc.class);
- objectStats.put(type, id);
- }
-
- try {
- Tracer tracer = TracerFactory.getTracer();
- tracer.getStatistic(id).recordObjectAllocation(size);
- tracer.getStatistic(ALLOCATIONS).recordAllocation(size);
- } catch (RuntimeException e) {
- e.printStackTrace();
- }
+ try {
+ TracerFactory.getTracer().getStatistic(ALLOCATIONS).recordAllocation(size);
+ } catch (RuntimeException e) {
+ // Do best effort here
}
}
private synchronized void notifyArray(@Nonnull Class<?> type, @Nonnegative long size,
@Nonnegative int count) {
- synchronized (AllocationWatcher.class) {
- StatisticId<ArrayAlloc> id = arrayStats.get(type);
- if (id == null) {
- String name = type.getName();
-
- id = new StatisticId<ArrayAlloc>("jack.allocation.array." + name,
- "Array allocation of type " + type.getName(), ArrayAllocImpl.class, ArrayAlloc.class);
- arrayStats.put(type, id);
- }
-
- try {
- Tracer tracer = TracerFactory.getTracer();
- tracer.getStatistic(id).recordObjectAllocation(count, size);
- tracer.getStatistic(ALLOCATIONS).recordAllocation(size);
- } catch (RuntimeException e) {
- e.printStackTrace();
- }
+ try {
+ TracerFactory.getTracer().getStatistic(ALLOCATIONS).recordAllocation(size);
+ } catch (RuntimeException e) {
+ // Do best effort here
}
}
diff --git a/sched/src/com/android/sched/util/log/tracer/watcher/DetailedAllocationWatcher.java b/sched/src/com/android/sched/util/log/tracer/watcher/DetailedAllocationWatcher.java
new file mode 100644
index 0000000..f8a97e3
--- /dev/null
+++ b/sched/src/com/android/sched/util/log/tracer/watcher/DetailedAllocationWatcher.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.util.log.tracer.watcher;
+
+import com.android.sched.util.codec.ImplementationName;
+import com.android.sched.util.log.EventType;
+import com.android.sched.util.log.Tracer;
+import com.android.sched.util.log.TracerFactory;
+import com.android.sched.util.log.stats.ArrayAlloc;
+import com.android.sched.util.log.stats.ArrayAllocImpl;
+import com.android.sched.util.log.stats.ObjectAlloc;
+import com.android.sched.util.log.stats.ObjectAllocImpl;
+import com.android.sched.util.log.stats.Statistic;
+import com.android.sched.util.log.stats.StatisticId;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+
+/**
+ * Class to watch {@link Object} creation and make detailed statistics about allocation.
+ */
+public class DetailedAllocationWatcher implements ObjectWatcher<Object> {
+ static class Statistics implements ObjectWatcher.Statistics {
+ @Override
+ public Iterator<Statistic> iterator() {
+ throw new AssertionError();
+ }
+ }
+
+ @Nonnull
+ private static final Map<Class<?>, StatisticId<ObjectAlloc>> objectStats =
+ new ConcurrentHashMap<Class<?>, StatisticId<ObjectAlloc>>();
+
+ @Nonnull
+ private static final Map<Class<?>, StatisticId<ArrayAlloc>> arrayStats =
+ new ConcurrentHashMap<Class<?>, StatisticId<ArrayAlloc>>();
+
+ @Override
+ public boolean notifyInstantiation(
+ @Nonnull Object object, @Nonnegative long size, int count, @Nonnull EventType notUsed) {
+ Class<?> type = object.getClass();
+
+ if (count == -1) {
+ notifyObject(type, size);
+ } else {
+ notifyArray(type, size, count);
+ }
+
+ return false;
+ }
+
+ private void notifyObject(@Nonnull Class<?> type, @Nonnegative long size) {
+ StatisticId<ObjectAlloc> id;
+
+ synchronized (DetailedAllocationWatcher.class) {
+ id = objectStats.get(type);
+ if (id == null) {
+ String name = type.getName();
+
+ id = new StatisticId<ObjectAlloc>("jack.allocation.object." + name,
+ "Object allocation of type " + name, ObjectAllocImpl.class,
+ ObjectAlloc.class);
+ objectStats.put(type, id);
+ }
+ }
+
+ try {
+ TracerFactory.getTracer().getStatistic(id).recordObjectAllocation(size);
+ } catch (RuntimeException e) {
+ // Do best effort here
+ }
+ }
+
+ private synchronized void notifyArray(@Nonnull Class<?> type, @Nonnegative long size,
+ @Nonnegative int count) {
+ StatisticId<ArrayAlloc> id;
+
+ synchronized (DetailedAllocationWatcher.class) {
+ id = arrayStats.get(type);
+ if (id == null) {
+ String name = type.getName();
+
+ id = new StatisticId<ArrayAlloc>("jack.allocation.array." + name,
+ "Array allocation of type " + name, ArrayAllocImpl.class, ArrayAlloc.class);
+ arrayStats.put(type, id);
+ }
+ }
+
+ try {
+ TracerFactory.getTracer().getStatistic(id).recordObjectAllocation(count, size);
+ } catch (RuntimeException e) {
+ // Do best effort here
+ }
+ }
+
+ @Override
+ @Nonnull
+ public ObjectWatcher.Statistics addSample(@Nonnull Object node,
+ @CheckForNull ObjectWatcher.Statistics raw, @Nonnull EventType type) {
+ throw new AssertionError();
+ }
+
+ /**
+ * Install a {@link DetailedAllocationWatcher}
+ */
+ @ImplementationName(iface = WatcherInstaller.class, name = "detailed-object-alloc")
+ public static class DetailedAllocationWatcherInstaller implements WatcherInstaller {
+ @Override
+ public void install(@Nonnull Tracer tracer) {
+ tracer.registerWatcher(Object.class, DetailedAllocationWatcher.class);
+ }
+ }
+}
diff --git a/sched/src/com/android/sched/vfs/AbstractVElement.java b/sched/src/com/android/sched/vfs/AbstractVElement.java
new file mode 100644
index 0000000..939f8bc
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/AbstractVElement.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.vfs;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Base class for implementing VElement.
+ */
+public abstract class AbstractVElement implements VElement {
+
+ @Nonnull
+ @Override
+ public String toString() {
+ return getLocation().getDescription();
+ }
+}
diff --git a/sched/src/com/android/sched/vfs/InputVDir.java b/sched/src/com/android/sched/vfs/InputVDir.java
new file mode 100644
index 0000000..f57636d
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/InputVDir.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.vfs;
+
+import java.util.Collection;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Virtual directory.
+ */
+public interface InputVDir extends VElement {
+
+ @Nonnull
+ Collection<? extends VElement> list();
+
+}
diff --git a/sched/src/com/android/sched/vfs/InputVFile.java b/sched/src/com/android/sched/vfs/InputVFile.java
new file mode 100644
index 0000000..3d7d2cd
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/InputVFile.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.vfs;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Virtual file.
+ */
+public interface InputVFile extends VElement {
+
+ @Nonnull
+ InputStream openRead() throws IOException;
+
+}
diff --git a/sched/src/com/android/sched/vfs/OutputVDir.java b/sched/src/com/android/sched/vfs/OutputVDir.java
new file mode 100644
index 0000000..622c553
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/OutputVDir.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.vfs;
+
+import java.io.IOException;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Virtual directory to write to.
+ */
+public interface OutputVDir extends VElement {
+
+ @Nonnull
+ OutputVFile createOutputVFile(@Nonnull String filePath) throws IOException;
+
+}
diff --git a/sched/src/com/android/sched/vfs/OutputVFile.java b/sched/src/com/android/sched/vfs/OutputVFile.java
new file mode 100644
index 0000000..32154b5
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/OutputVFile.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.vfs;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Virtual file to write to.
+ */
+public interface OutputVFile extends VElement {
+
+ @Nonnull
+ OutputStream openWrite() throws IOException;
+
+}
diff --git a/sched/src/com/android/sched/vfs/VElement.java b/sched/src/com/android/sched/vfs/VElement.java
new file mode 100644
index 0000000..748b9bd
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/VElement.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.vfs;
+
+import com.android.sched.util.config.Location;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Element of a virtual file system.
+ */
+public interface VElement {
+
+ @Nonnull
+ String getName();
+
+ @Nonnull
+ public Location getLocation();
+
+}
diff --git a/sched/src/com/android/sched/vfs/direct/InputDirectDir.java b/sched/src/com/android/sched/vfs/direct/InputDirectDir.java
new file mode 100644
index 0000000..4e88043
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/direct/InputDirectDir.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.vfs.direct;
+
+import com.android.sched.util.ConcurrentIOException;
+import com.android.sched.util.config.FileLocation;
+import com.android.sched.util.config.Location;
+import com.android.sched.util.file.NotFileOrDirectoryException;
+import com.android.sched.vfs.AbstractVElement;
+import com.android.sched.vfs.InputVDir;
+import com.android.sched.vfs.VElement;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * Directory in the file system.
+ */
+public class InputDirectDir extends AbstractVElement implements InputVDir {
+
+ @Nonnull
+ private final File dir;
+ @CheckForNull
+ private ArrayList<VElement> list;
+
+ public InputDirectDir(@Nonnull File dir) throws NotFileOrDirectoryException {
+ if (!dir.isDirectory()) {
+ throw new NotFileOrDirectoryException(dir.getAbsolutePath(), false);
+ }
+ this.dir = dir;
+ }
+
+ @Nonnull
+ @Override
+ public String getName() {
+ return dir.getName();
+ }
+
+ @Nonnull
+ @Override
+ public synchronized Collection<? extends VElement> list() {
+ if (list == null) {
+ File[] subs = dir.listFiles();
+ if (subs == null) {
+ throw new ConcurrentIOException(new ListDirException(dir));
+ }
+ if (subs.length == 0) {
+ return Collections.emptyList();
+ }
+
+ list = new ArrayList<VElement>(subs.length);
+ for (File sub : subs) {
+ try {
+ if (sub.isFile()) {
+ list.add(new InputDirectFile(sub));
+ } else {
+ list.add(new InputDirectDir(sub));
+ }
+ } catch (NotFileOrDirectoryException e) {
+ throw new ConcurrentIOException(e);
+ }
+ }
+ }
+
+ assert list != null;
+ return list;
+ }
+
+ @Override
+ @Nonnull
+ public Location getLocation() {
+ return new FileLocation(dir);
+ }
+}
diff --git a/sched/src/com/android/sched/vfs/direct/InputDirectFile.java b/sched/src/com/android/sched/vfs/direct/InputDirectFile.java
new file mode 100644
index 0000000..45ae9ab
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/direct/InputDirectFile.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.vfs.direct;
+
+import com.android.sched.util.config.FileLocation;
+import com.android.sched.util.config.Location;
+import com.android.sched.util.file.NotFileOrDirectoryException;
+import com.android.sched.vfs.AbstractVElement;
+import com.android.sched.vfs.InputVFile;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A {@code VFile} directly backed but a {@code java.io.File}.
+ */
+public class InputDirectFile extends AbstractVElement implements InputVFile {
+
+ @Nonnull
+ private final File file;
+
+ public InputDirectFile(@Nonnull File file) throws NotFileOrDirectoryException {
+ if (!file.isFile()) {
+ throw new NotFileOrDirectoryException(file.getAbsolutePath(), true);
+ }
+ this.file = file;
+ }
+
+ @Nonnull
+ @Override
+ public InputStream openRead() throws FileNotFoundException {
+ return new FileInputStream(file);
+ }
+
+ @Nonnull
+ @Override
+ public String getName() {
+ return file.getName();
+ }
+
+ @Override
+ @Nonnull
+ public Location getLocation() {
+ return new FileLocation(file);
+ }
+}
diff --git a/sched/src/com/android/sched/vfs/direct/ListDirException.java b/sched/src/com/android/sched/vfs/direct/ListDirException.java
new file mode 100644
index 0000000..802c9d4
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/direct/ListDirException.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.vfs.direct;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Thrown when listing a directory content failed.
+ */
+public class ListDirException extends IOException {
+
+ private static final long serialVersionUID = 1L;
+ @Nonnull
+ private final File dir;
+
+ public ListDirException(@Nonnull File dir) {
+ this.dir = dir;
+ }
+
+ @Override
+ public String getMessage() {
+ return "Failed to list directory content '" + dir.getPath() + "'";
+ }
+}
diff --git a/sched/src/com/android/sched/vfs/direct/OutputDirectDir.java b/sched/src/com/android/sched/vfs/direct/OutputDirectDir.java
new file mode 100644
index 0000000..58968b1
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/direct/OutputDirectDir.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.vfs.direct;
+
+import com.android.sched.util.config.FileLocation;
+import com.android.sched.util.config.Location;
+import com.android.sched.util.file.CannotCreateFileException;
+import com.android.sched.util.file.Directory;
+import com.android.sched.util.file.FileAlreadyExistsException;
+import com.android.sched.vfs.AbstractVElement;
+import com.android.sched.vfs.OutputVDir;
+import com.android.sched.vfs.OutputVFile;
+
+import java.io.File;
+
+import javax.annotation.Nonnull;
+
+/**
+ * An {@link OutputVDir} using a real directory.
+ */
+public class OutputDirectDir extends AbstractVElement implements OutputVDir {
+
+ @Nonnull
+ private final File dir;
+
+ public OutputDirectDir(@Nonnull Directory dir) {
+ this.dir = dir.getFile();
+ }
+
+ @Nonnull
+ @Override
+ public String getName() {
+ return dir.getName();
+ }
+
+ @Override
+ @Nonnull
+ public Location getLocation() {
+ return new FileLocation(dir);
+ }
+
+ @Override
+ @Nonnull
+ public OutputVFile createOutputVFile(@Nonnull String filePath) throws CannotCreateFileException,
+ FileAlreadyExistsException {
+ File file = new File(dir, filePath);
+ if (!file.getParentFile().mkdirs() && !file.getParentFile().isDirectory()) {
+ throw new CannotCreateFileException(file.getParentFile().getAbsolutePath(),
+ /* isFile */ false);
+ }
+ return new OutputDirectFile(file);
+ }
+}
diff --git a/sched/src/com/android/sched/vfs/direct/OutputDirectFile.java b/sched/src/com/android/sched/vfs/direct/OutputDirectFile.java
new file mode 100644
index 0000000..58b36e9
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/direct/OutputDirectFile.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.vfs.direct;
+
+import com.android.sched.util.config.FileLocation;
+import com.android.sched.util.config.Location;
+import com.android.sched.util.file.FileAlreadyExistsException;
+import com.android.sched.vfs.AbstractVElement;
+import com.android.sched.vfs.OutputVFile;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+
+import javax.annotation.Nonnull;
+
+/**
+ * An {@link OutputVFile} directly backed by a {@link File} directory.
+ */
+class OutputDirectFile extends AbstractVElement implements OutputVFile {
+
+ private static boolean checkIfFileAlreadyExists = false;
+
+ @Nonnull
+ private final File file;
+
+ public OutputDirectFile(@Nonnull File file) throws FileAlreadyExistsException {
+ if (checkIfFileAlreadyExists && file.exists()) {
+ throw new FileAlreadyExistsException(file.getAbsolutePath(), !file.isDirectory());
+ }
+ this.file = file;
+ }
+
+ @Nonnull
+ @Override
+ public OutputStream openWrite() throws FileNotFoundException {
+ return new FileOutputStream(file);
+ }
+
+ @Nonnull
+ @Override
+ public String getName() {
+ return file.getPath();
+ }
+
+ @Override
+ @Nonnull
+ public Location getLocation() {
+ return new FileLocation(file);
+ }
+}
diff --git a/sched/src/com/android/sched/vfs/zip/InputZipArchive.java b/sched/src/com/android/sched/vfs/zip/InputZipArchive.java
new file mode 100644
index 0000000..fec4e36
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/zip/InputZipArchive.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.vfs.zip;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Virtual directory for viewing the content of a zip file.
+ */
+public class InputZipArchive extends InputZipVDir implements Closeable {
+
+ @Nonnull
+ public static final String IN_ZIP_SEPARATOR = "/";
+
+ @Nonnull
+ private final ZipFile zip;
+
+ public InputZipArchive(@Nonnull File zipFile) throws IOException {
+ super("", zipFile, new ZipEntry(""));
+
+ zip = new ZipFile(zipFile);
+
+ for (Enumeration<? extends ZipEntry> entries = zip.entries(); entries.hasMoreElements();) {
+ ZipEntry entry = entries.nextElement();
+ if (!entry.isDirectory()) {
+ String entryName = entry.getName();
+ String[] names = entryName.split(IN_ZIP_SEPARATOR);
+ @SuppressWarnings("resource")
+ InputZipVDir dir = this;
+ StringBuilder inZipPath = new StringBuilder();
+ for (int i = 0; i < names.length - 1; i++) {
+ String simpleName = names[i];
+ inZipPath.append(IN_ZIP_SEPARATOR).append(simpleName);
+ InputZipVDir nextDir = (InputZipVDir) dir.subs.get(simpleName);
+ if (nextDir == null) {
+ nextDir = new InputZipVDir(simpleName, zipFile, new ZipEntry(inZipPath.toString()));
+ dir.subs.put(simpleName, nextDir);
+ }
+ dir = nextDir;
+ }
+ String simpleName = names[names.length - 1];
+ dir.subs.put(simpleName, new InputZipVFile(simpleName, zip, entry));
+ }
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ zip.close();
+ }
+}
diff --git a/sched/src/com/android/sched/vfs/zip/InputZipVDir.java b/sched/src/com/android/sched/vfs/zip/InputZipVDir.java
new file mode 100644
index 0000000..7ad1cc5
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/zip/InputZipVDir.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.vfs.zip;
+
+import com.android.sched.util.config.FileLocation;
+import com.android.sched.util.config.Location;
+import com.android.sched.util.config.ZipLocation;
+import com.android.sched.vfs.AbstractVElement;
+import com.android.sched.vfs.InputVDir;
+import com.android.sched.vfs.VElement;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.zip.ZipEntry;
+
+import javax.annotation.Nonnull;
+
+class InputZipVDir extends AbstractVElement implements InputVDir {
+
+ @Nonnull
+ protected final HashMap<String, VElement> subs = new HashMap<String, VElement>();
+ @Nonnull
+ private final String name;
+
+ @Nonnull
+ private final Location location;
+
+ InputZipVDir(@Nonnull String name, @Nonnull File zip, @Nonnull ZipEntry entry) {
+ this.name = name;
+ this.location = new ZipLocation(new FileLocation(zip), entry);
+ }
+
+ @Nonnull
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Nonnull
+ @Override
+ public Collection<? extends VElement> list() {
+ return subs.values();
+ }
+
+ @Override
+ @Nonnull
+ public Location getLocation() {
+ return location;
+ }
+
+}
diff --git a/sched/src/com/android/sched/vfs/zip/InputZipVFile.java b/sched/src/com/android/sched/vfs/zip/InputZipVFile.java
new file mode 100644
index 0000000..090dc2f
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/zip/InputZipVFile.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.vfs.zip;
+
+import com.android.sched.util.config.FileLocation;
+import com.android.sched.util.config.Location;
+import com.android.sched.util.config.ZipLocation;
+import com.android.sched.vfs.AbstractVElement;
+import com.android.sched.vfs.InputVFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import javax.annotation.Nonnull;
+
+class InputZipVFile extends AbstractVElement implements InputVFile {
+
+ @Nonnull
+ private final String name;
+ @Nonnull
+ private final ZipFile zip;
+ @Nonnull
+ private final ZipEntry entry;
+
+ InputZipVFile(@Nonnull String name, @Nonnull ZipFile zip, @Nonnull ZipEntry entry) {
+ this.name = name;
+ this.zip = zip;
+ this.entry = entry;
+ }
+
+ @Nonnull
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Nonnull
+ @Override
+ public InputStream openRead() throws IOException {
+ return zip.getInputStream(entry);
+ }
+
+ @Override
+ @Nonnull
+ public Location getLocation() {
+ return new ZipLocation(new FileLocation(new File(zip.getName())), entry);
+ }
+
+}
diff --git a/sched/src/com/android/sched/vfs/zip/OutputZipRootVDir.java b/sched/src/com/android/sched/vfs/zip/OutputZipRootVDir.java
new file mode 100644
index 0000000..b1b6ae1
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/zip/OutputZipRootVDir.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.vfs.zip;
+
+import com.android.sched.util.config.FileLocation;
+import com.android.sched.util.config.Location;
+import com.android.sched.util.config.ZipLocation;
+import com.android.sched.vfs.AbstractVElement;
+import com.android.sched.vfs.OutputVDir;
+import com.android.sched.vfs.OutputVFile;
+import com.android.sched.vfs.VElement;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A root {@link OutputVDir} backed by a zip archive.
+ */
+public class OutputZipRootVDir extends AbstractVElement implements OutputVDir, Closeable {
+
+ @Nonnull
+ protected final HashMap<String, VElement> subs = new HashMap<String, VElement>();
+ @Nonnull
+ private final Location location;
+ @Nonnull
+ protected final ZipOutputStream zos;
+ @Nonnull
+ private final File zipFile;
+
+ public OutputZipRootVDir(@Nonnull File zipFile) throws FileNotFoundException {
+ this.zipFile = zipFile;
+ location = new ZipLocation(new FileLocation(zipFile), new ZipEntry(""));
+ zos = new ZipOutputStream(new FileOutputStream(zipFile));
+ }
+
+ @Nonnull
+ @Override
+ public String getName() {
+ return zipFile.getName();
+ }
+
+ @Override
+ @Nonnull
+ public Location getLocation() {
+ return location;
+ }
+
+ @Override
+ @Nonnull
+ public OutputVFile createOutputVFile(@Nonnull String filePath) {
+ return new OutputZipVFile(zos, new ZipEntry(filePath), zipFile);
+ }
+
+ @Override
+ public void close() throws IOException {
+ zos.close();
+ }
+}
diff --git a/sched/src/com/android/sched/vfs/zip/OutputZipVFile.java b/sched/src/com/android/sched/vfs/zip/OutputZipVFile.java
new file mode 100644
index 0000000..afee54d
--- /dev/null
+++ b/sched/src/com/android/sched/vfs/zip/OutputZipVFile.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed 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 com.android.sched.vfs.zip;
+
+import com.android.sched.util.config.FileLocation;
+import com.android.sched.util.config.Location;
+import com.android.sched.util.config.ZipLocation;
+import com.android.sched.util.stream.UncloseableOutputStream;
+import com.android.sched.vfs.AbstractVElement;
+import com.android.sched.vfs.OutputVFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import javax.annotation.Nonnull;
+
+class OutputZipVFile extends AbstractVElement implements OutputVFile {
+
+ @Nonnull
+ private final ZipOutputStream zos;
+ @Nonnull
+ private final ZipEntry entry;
+ @Nonnull
+ private final Location location;
+
+ OutputZipVFile(@Nonnull ZipOutputStream zos, @Nonnull ZipEntry entry, @Nonnull File zipFile) {
+ this.zos = zos;
+ this.entry = entry;
+ location = new ZipLocation(new FileLocation(zipFile), entry);
+ }
+
+ @Nonnull
+ @Override
+ public String getName() {
+ return entry.getName();
+ }
+
+ @Nonnull
+ @Override
+ public OutputStream openWrite() throws IOException {
+ zos.putNextEntry(entry);
+ return new UncloseableOutputStream(zos);
+ }
+
+ @Override
+ @Nonnull
+ public Location getLocation() {
+ return location;
+ }
+
+}