initial commit
This commit is contained in:
commit
3aca31de74
40 changed files with 1701 additions and 0 deletions
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
*.java text eol=lf
|
||||||
|
*.c text eol=lf
|
||||||
|
*.h text eol=lf
|
||||||
|
*.bat text eol=crlf
|
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
bin/
|
||||||
|
cs/archive
|
||||||
|
twits/hello/hello
|
||||||
|
twits/intset/example
|
||||||
|
twits/intset/unittest
|
||||||
|
twits/server/msg_server
|
||||||
|
twits/*/*.exe
|
||||||
|
.DS_Store
|
||||||
|
*~
|
11
clock/.classpath
Executable file
11
clock/.classpath
Executable file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="module" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="lib" path="/cs/labs.jar"/>
|
||||||
|
<classpathentry kind="output" path="bin"/>
|
||||||
|
</classpath>
|
28
clock/.project
Executable file
28
clock/.project
Executable file
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>1. Alarm clock</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
<filteredResources>
|
||||||
|
<filter>
|
||||||
|
<id>1678721711427</id>
|
||||||
|
<name></name>
|
||||||
|
<type>30</type>
|
||||||
|
<matcher>
|
||||||
|
<id>org.eclipse.core.resources.regexFilterMatcher</id>
|
||||||
|
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
|
||||||
|
</matcher>
|
||||||
|
</filter>
|
||||||
|
</filteredResources>
|
||||||
|
</projectDescription>
|
2
clock/.settings/org.eclipse.core.resources.prefs
Normal file
2
clock/.settings/org.eclipse.core.resources.prefs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding/<project>=UTF-8
|
26
clock/src/ClockMain.java
Normal file
26
clock/src/ClockMain.java
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import clock.AlarmClockEmulator;
|
||||||
|
import clock.io.Choice;
|
||||||
|
import clock.io.ClockInput;
|
||||||
|
import clock.io.ClockInput.UserInput;
|
||||||
|
import clock.io.ClockOutput;
|
||||||
|
|
||||||
|
public class ClockMain {
|
||||||
|
public static void main(String[] args) throws InterruptedException {
|
||||||
|
AlarmClockEmulator emulator = new AlarmClockEmulator();
|
||||||
|
|
||||||
|
ClockInput in = emulator.getInput();
|
||||||
|
ClockOutput out = emulator.getOutput();
|
||||||
|
|
||||||
|
out.displayTime(15, 2, 37); // arbitrary time: just an example
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
UserInput userInput = in.getUserInput();
|
||||||
|
Choice c = userInput.choice();
|
||||||
|
int h = userInput.hours();
|
||||||
|
int m = userInput.minutes();
|
||||||
|
int s = userInput.seconds();
|
||||||
|
|
||||||
|
System.out.println("choice=" + c + " h=" + h + " m=" + m + " s=" + s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
clock/src/clock/io/Choice.java
Normal file
7
clock/src/clock/io/Choice.java
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package clock.io;
|
||||||
|
|
||||||
|
public enum Choice {
|
||||||
|
SET_TIME, // user set new clock time
|
||||||
|
SET_ALARM, // user set new alarm time
|
||||||
|
TOGGLE_ALARM; // user pressed both buttons simultaneously
|
||||||
|
}
|
43
clock/src/clock/io/ClockInput.java
Normal file
43
clock/src/clock/io/ClockInput.java
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
package clock.io;
|
||||||
|
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input signals from clock hardware.
|
||||||
|
*
|
||||||
|
* NOTE: you are not expected to modify this interface,
|
||||||
|
* nor to implement it yourself. Instead, to read from
|
||||||
|
* the emulated hardware, do as follows:
|
||||||
|
*
|
||||||
|
* AlarmClockEmulator emulator = new AlarmClockEmulator();
|
||||||
|
* ClockInput in = emulator.getInput();
|
||||||
|
*
|
||||||
|
* Then use the reference 'in' to read the input signals.
|
||||||
|
*/
|
||||||
|
public interface ClockInput {
|
||||||
|
|
||||||
|
/** @return semaphore signaled on user input (via hardware interrupt) */
|
||||||
|
Semaphore getSemaphore();
|
||||||
|
|
||||||
|
/** @return an item of user input (available only when semaphore is signaled) */
|
||||||
|
UserInput getUserInput();
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** An item of input, entered by the user. */
|
||||||
|
interface UserInput {
|
||||||
|
/** @return a value indicating the type of choice made by the user. */
|
||||||
|
Choice choice();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These methods return a time set by the user (clock time or alarm time).
|
||||||
|
*
|
||||||
|
* If choice() returns SET_TIME, these return the time the user entered.
|
||||||
|
* If choice() returns SET_ALARM, these return the alarm time the user entered.
|
||||||
|
* If choice() returns TOGGLE_ALARM, these return an invalid value.
|
||||||
|
*/
|
||||||
|
int hours();
|
||||||
|
int minutes();
|
||||||
|
int seconds();
|
||||||
|
}
|
||||||
|
}
|
26
clock/src/clock/io/ClockOutput.java
Normal file
26
clock/src/clock/io/ClockOutput.java
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package clock.io;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output signals to clock hardware.
|
||||||
|
*
|
||||||
|
* NOTE: you are not expected to modify this interface,
|
||||||
|
* nor to implement it yourself. Instead, to control
|
||||||
|
* the emulated hardware, do as follows:
|
||||||
|
*
|
||||||
|
* AlarmClockEmulator emulator = new AlarmClockEmulator();
|
||||||
|
* ClockInput out = emulator.getoutput();
|
||||||
|
*
|
||||||
|
* Then use the reference 'out' to control the output signals.
|
||||||
|
*/
|
||||||
|
public interface ClockOutput {
|
||||||
|
|
||||||
|
/** Display the given time on the display, for example (15, 2, 37) for
|
||||||
|
15 hours, 2 minutes and 37 seconds since midnight. */
|
||||||
|
void displayTime(int hours, int mins, int secs);
|
||||||
|
|
||||||
|
/** Indicate on the display whether the alarm is on or off. */
|
||||||
|
void setAlarmIndicator(boolean on);
|
||||||
|
|
||||||
|
/** Signal the alarm. (In the emulator, only a visual alarm is given.) */
|
||||||
|
void alarm();
|
||||||
|
}
|
6
cs/.classpath
Normal file
6
cs/.classpath
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||||
|
<classpathentry kind="output" path="bin"/>
|
||||||
|
</classpath>
|
37
cs/.project
Normal file
37
cs/.project
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>cs</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
<filteredResources>
|
||||||
|
<filter>
|
||||||
|
<id>1665396157120</id>
|
||||||
|
<name></name>
|
||||||
|
<type>26</type>
|
||||||
|
<matcher>
|
||||||
|
<id>org.eclipse.ui.ide.multiFilter</id>
|
||||||
|
<arguments>1.0-projectRelativePath-matches-false-false-archive</arguments>
|
||||||
|
</matcher>
|
||||||
|
</filter>
|
||||||
|
<filter>
|
||||||
|
<id>1678721711433</id>
|
||||||
|
<name></name>
|
||||||
|
<type>30</type>
|
||||||
|
<matcher>
|
||||||
|
<id>org.eclipse.core.resources.regexFilterMatcher</id>
|
||||||
|
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
|
||||||
|
</matcher>
|
||||||
|
</filter>
|
||||||
|
</filteredResources>
|
||||||
|
</projectDescription>
|
2
cs/.settings/org.eclipse.core.resources.prefs
Normal file
2
cs/.settings/org.eclipse.core.resources.prefs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding/<project>=UTF-8
|
104
cs/.settings/org.eclipse.jdt.core.prefs
Normal file
104
cs/.settings/org.eclipse.jdt.core.prefs
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.builder.annotationPath.allLocations=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
|
||||||
|
org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
|
||||||
|
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
|
||||||
|
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
|
||||||
|
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
|
||||||
|
org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
|
||||||
|
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.APILeak=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated=info
|
||||||
|
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.deadCode=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.deprecation=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
|
||||||
|
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
|
||||||
|
org.eclipse.jdt.core.compiler.problem.nullReference=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
|
||||||
|
org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.suppressWarningsNotFullyAnalysed=info
|
||||||
|
org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unclosedCloseable=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
|
212
cs/junit/README.md
Normal file
212
cs/junit/README.md
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
The file junit-platform-console-standalone-X.Y.Z.jar contains runtime
|
||||||
|
support for JUnit tests. Downloaded from:
|
||||||
|
|
||||||
|
https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone/1.9.2/
|
||||||
|
|
||||||
|
Licensed under the EPL (Eclipse Public License): see below.
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
Eclipse Public License - v 1.0
|
||||||
|
|
||||||
|
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
|
||||||
|
PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE
|
||||||
|
PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
|
||||||
|
|
||||||
|
1. DEFINITIONS
|
||||||
|
|
||||||
|
"Contribution" means:
|
||||||
|
|
||||||
|
a) in the case of the initial Contributor, the initial code and
|
||||||
|
documentation distributed under this Agreement, and
|
||||||
|
b) in the case of each subsequent Contributor:
|
||||||
|
i) changes to the Program, and
|
||||||
|
ii) additions to the Program;
|
||||||
|
where such changes and/or additions to the Program originate from and are
|
||||||
|
distributed by that particular Contributor. A Contribution 'originates'
|
||||||
|
from a Contributor if it was added to the Program by such Contributor
|
||||||
|
itself or anyone acting on such Contributor's behalf. Contributions do not
|
||||||
|
include additions to the Program which: (i) are separate modules of
|
||||||
|
software distributed in conjunction with the Program under their own
|
||||||
|
license agreement, and (ii) are not derivative works of the Program.
|
||||||
|
"Contributor" means any person or entity that distributes the Program.
|
||||||
|
|
||||||
|
"Licensed Patents" mean patent claims licensable by a Contributor which
|
||||||
|
are necessarily infringed by the use or sale of its Contribution alone or
|
||||||
|
when combined with the Program.
|
||||||
|
|
||||||
|
"Program" means the Contributions distributed in accordance with this
|
||||||
|
Agreement.
|
||||||
|
|
||||||
|
"Recipient" means anyone who receives the Program under this Agreement,
|
||||||
|
including all Contributors.
|
||||||
|
|
||||||
|
2. GRANT OF RIGHTS
|
||||||
|
|
||||||
|
a) Subject to the terms of this Agreement, each Contributor hereby grants
|
||||||
|
Recipient a non-exclusive, worldwide, royalty-free copyright license to
|
||||||
|
reproduce, prepare derivative works of, publicly display, publicly
|
||||||
|
perform, distribute and sublicense the Contribution of such Contributor,
|
||||||
|
if any, and such derivative works, in source code and object code form.
|
||||||
|
b) Subject to the terms of this Agreement, each Contributor hereby grants
|
||||||
|
Recipient a non-exclusive, worldwide, royalty-free patent license under
|
||||||
|
Licensed Patents to make, use, sell, offer to sell, import and otherwise
|
||||||
|
transfer the Contribution of such Contributor, if any, in source code and
|
||||||
|
object code form. This patent license shall apply to the combination of
|
||||||
|
the Contribution and the Program if, at the time the Contribution is added
|
||||||
|
by the Contributor, such addition of the Contribution causes such
|
||||||
|
combination to be covered by the Licensed Patents. The patent license
|
||||||
|
shall not apply to any other combinations which include the Contribution.
|
||||||
|
No hardware per se is licensed hereunder.
|
||||||
|
c) Recipient understands that although each Contributor grants the
|
||||||
|
licenses to its Contributions set forth herein, no assurances are provided
|
||||||
|
by any Contributor that the Program does not infringe the patent or other
|
||||||
|
intellectual property rights of any other entity. Each Contributor
|
||||||
|
disclaims any liability to Recipient for claims brought by any other
|
||||||
|
entity based on infringement of intellectual property rights or otherwise.
|
||||||
|
As a condition to exercising the rights and licenses granted hereunder,
|
||||||
|
each Recipient hereby assumes sole responsibility to secure any other
|
||||||
|
intellectual property rights needed, if any. For example, if a third party
|
||||||
|
patent license is required to allow Recipient to distribute the Program,
|
||||||
|
it is Recipient's responsibility to acquire that license before
|
||||||
|
distributing the Program.
|
||||||
|
d) Each Contributor represents that to its knowledge it has sufficient
|
||||||
|
copyright rights in its Contribution, if any, to grant the copyright
|
||||||
|
license set forth in this Agreement.
|
||||||
|
3. REQUIREMENTS
|
||||||
|
|
||||||
|
A Contributor may choose to distribute the Program in object code form
|
||||||
|
under its own license agreement, provided that:
|
||||||
|
|
||||||
|
a) it complies with the terms and conditions of this Agreement; and
|
||||||
|
b) its license agreement:
|
||||||
|
i) effectively disclaims on behalf of all Contributors all warranties and
|
||||||
|
conditions, express and implied, including warranties or conditions of
|
||||||
|
title and non-infringement, and implied warranties or conditions of
|
||||||
|
merchantability and fitness for a particular purpose;
|
||||||
|
ii) effectively excludes on behalf of all Contributors all liability for
|
||||||
|
damages, including direct, indirect, special, incidental and consequential
|
||||||
|
damages, such as lost profits;
|
||||||
|
iii) states that any provisions which differ from this Agreement are
|
||||||
|
offered by that Contributor alone and not by any other party; and
|
||||||
|
iv) states that source code for the Program is available from such
|
||||||
|
Contributor, and informs licensees how to obtain it in a reasonable manner
|
||||||
|
on or through a medium customarily used for software exchange.
|
||||||
|
When the Program is made available in source code form:
|
||||||
|
|
||||||
|
a) it must be made available under this Agreement; and
|
||||||
|
b) a copy of this Agreement must be included with each copy of the
|
||||||
|
Program.
|
||||||
|
Contributors may not remove or alter any copyright notices contained
|
||||||
|
within the Program.
|
||||||
|
|
||||||
|
Each Contributor must identify itself as the originator of its
|
||||||
|
Contribution, if any, in a manner that reasonably allows subsequent
|
||||||
|
Recipients to identify the originator of the Contribution.
|
||||||
|
|
||||||
|
4. COMMERCIAL DISTRIBUTION
|
||||||
|
|
||||||
|
Commercial distributors of software may accept certain responsibilities
|
||||||
|
with respect to end users, business partners and the like. While this
|
||||||
|
license is intended to facilitate the commercial use of the Program, the
|
||||||
|
Contributor who includes the Program in a commercial product offering
|
||||||
|
should do so in a manner which does not create potential liability for
|
||||||
|
other Contributors. Therefore, if a Contributor includes the Program in a
|
||||||
|
commercial product offering, such Contributor ("Commercial Contributor")
|
||||||
|
hereby agrees to defend and indemnify every other Contributor
|
||||||
|
("Indemnified Contributor") against any losses, damages and costs
|
||||||
|
(collectively "Losses") arising from claims, lawsuits and other legal
|
||||||
|
actions brought by a third party against the Indemnified Contributor to
|
||||||
|
the extent caused by the acts or omissions of such Commercial Contributor
|
||||||
|
in connection with its distribution of the Program in a commercial product
|
||||||
|
offering. The obligations in this section do not apply to any claims or
|
||||||
|
Losses relating to any actual or alleged intellectual property
|
||||||
|
infringement. In order to qualify, an Indemnified Contributor must: a)
|
||||||
|
promptly notify the Commercial Contributor in writing of such claim, and
|
||||||
|
b) allow the Commercial Contributor to control, and cooperate with the
|
||||||
|
Commercial Contributor in, the defense and any related settlement
|
||||||
|
negotiations. The Indemnified Contributor may participate in any such
|
||||||
|
claim at its own expense.
|
||||||
|
|
||||||
|
For example, a Contributor might include the Program in a commercial
|
||||||
|
product offering, Product X. That Contributor is then a Commercial
|
||||||
|
Contributor. If that Commercial Contributor then makes performance claims,
|
||||||
|
or offers warranties related to Product X, those performance claims and
|
||||||
|
warranties are such Commercial Contributor's responsibility alone. Under
|
||||||
|
this section, the Commercial Contributor would have to defend claims
|
||||||
|
against the other Contributors related to those performance claims and
|
||||||
|
warranties, and if a court requires any other Contributor to pay any
|
||||||
|
damages as a result, the Commercial Contributor must pay those damages.
|
||||||
|
|
||||||
|
5. NO WARRANTY
|
||||||
|
|
||||||
|
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED
|
||||||
|
ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
|
||||||
|
EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR
|
||||||
|
CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. Each Recipient is solely responsible for determining
|
||||||
|
the appropriateness of using and distributing the Program and assumes all
|
||||||
|
risks associated with its exercise of rights under this Agreement ,
|
||||||
|
including but not limited to the risks and costs of program errors,
|
||||||
|
compliance with applicable laws, damage to or loss of data, programs or
|
||||||
|
equipment, and unavailability or interruption of operations.
|
||||||
|
|
||||||
|
6. DISCLAIMER OF LIABILITY
|
||||||
|
|
||||||
|
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
|
||||||
|
CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
|
||||||
|
WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION
|
||||||
|
OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
7. GENERAL
|
||||||
|
|
||||||
|
If any provision of this Agreement is invalid or unenforceable under
|
||||||
|
applicable law, it shall not affect the validity or enforceability of the
|
||||||
|
remainder of the terms of this Agreement, and without further action by
|
||||||
|
the parties hereto, such provision shall be reformed to the minimum extent
|
||||||
|
necessary to make such provision valid and enforceable.
|
||||||
|
|
||||||
|
If Recipient institutes patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Program itself
|
||||||
|
(excluding combinations of the Program with other software or hardware)
|
||||||
|
infringes such Recipient's patent(s), then such Recipient's rights granted
|
||||||
|
under Section 2(b) shall terminate as of the date such litigation is
|
||||||
|
filed.
|
||||||
|
|
||||||
|
All Recipient's rights under this Agreement shall terminate if it fails to
|
||||||
|
comply with any of the material terms or conditions of this Agreement and
|
||||||
|
does not cure such failure in a reasonable period of time after becoming
|
||||||
|
aware of such noncompliance. If all Recipient's rights under this
|
||||||
|
Agreement terminate, Recipient agrees to cease use and distribution of the
|
||||||
|
Program as soon as reasonably practicable. However, Recipient's
|
||||||
|
obligations under this Agreement and any licenses granted by Recipient
|
||||||
|
relating to the Program shall continue and survive.
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute copies of this Agreement, but
|
||||||
|
in order to avoid inconsistency the Agreement is copyrighted and may only
|
||||||
|
be modified in the following manner. The Agreement Steward reserves the
|
||||||
|
right to publish new versions (including revisions) of this Agreement from
|
||||||
|
time to time. No one other than the Agreement Steward has the right to
|
||||||
|
modify this Agreement. The Eclipse Foundation is the initial Agreement
|
||||||
|
Steward. The Eclipse Foundation may assign the responsibility to serve as
|
||||||
|
the Agreement Steward to a suitable separate entity. Each new version of
|
||||||
|
the Agreement will be given a distinguishing version number. The Program
|
||||||
|
(including Contributions) may always be distributed subject to the version
|
||||||
|
of the Agreement under which it was received. In addition, after a new
|
||||||
|
version of the Agreement is published, Contributor may elect to distribute
|
||||||
|
the Program (including its Contributions) under the new version. Except as
|
||||||
|
expressly stated in Sections 2(a) and 2(b) above, Recipient receives no
|
||||||
|
rights or licenses to the intellectual property of any Contributor under
|
||||||
|
this Agreement, whether expressly, by implication, estoppel or otherwise.
|
||||||
|
All rights in the Program not expressly granted under this Agreement are
|
||||||
|
reserved.
|
||||||
|
|
||||||
|
This Agreement is governed by the laws of the State of New York and the
|
||||||
|
intellectual property laws of the United States of America. No party to
|
||||||
|
this Agreement will bring a legal action under this Agreement more than
|
||||||
|
one year after the cause of action arose. Each party waives its rights to
|
||||||
|
a jury trial in any resulting litigation.
|
BIN
cs/junit/junit-platform-console-standalone-1.9.2.jar
Normal file
BIN
cs/junit/junit-platform-console-standalone-1.9.2.jar
Normal file
Binary file not shown.
BIN
cs/labs.jar
Normal file
BIN
cs/labs.jar
Normal file
Binary file not shown.
173
cs/src/UpdateLabCode.java
Normal file
173
cs/src/UpdateLabCode.java
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
/**
|
||||||
|
** Simple application to update cs/labs.jar to the most recent version.
|
||||||
|
**
|
||||||
|
** The labs.jar file is fetched from the gitlab.com repository.
|
||||||
|
**/
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.FlowLayout;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse.BodyHandlers;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.jar.Attributes;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
|
||||||
|
public class UpdateLabCode extends JFrame {
|
||||||
|
|
||||||
|
private static final URI DOWNLOAD_URI = URI.create("https://gitlab.com/api/v4/projects/edaf85%2Fedaf85-labs/repository/files/cs%2Flabs.jar/raw?ref=main");
|
||||||
|
|
||||||
|
private final JLabel messageArea = new JLabel("", SwingConstants.CENTER);
|
||||||
|
private final JPanel buttonArea = new JPanel(new FlowLayout(FlowLayout.RIGHT, 20, 20));
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
public UpdateLabCode() {
|
||||||
|
super("Update lab code (EDAF85, fall 2024)");
|
||||||
|
|
||||||
|
add(messageArea, BorderLayout.CENTER);
|
||||||
|
add(buttonArea, BorderLayout.SOUTH);
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<Path> candidates = Files.walk(Path.of(System.getProperty("user.dir")).getParent())
|
||||||
|
.filter(Files::isRegularFile)
|
||||||
|
.filter(f -> f.endsWith(Path.of("cs", "labs.jar")))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (candidates.size() == 1) {
|
||||||
|
showDialog("Currently using version: " + getJarVersion(candidates.get(0)),
|
||||||
|
"Check for update", () -> check(candidates.get(0)));
|
||||||
|
} else {
|
||||||
|
if (candidates.size() != 0) {
|
||||||
|
System.err.println("*** ERROR: found multiple 'cs/labs.jar', cannot decide which one to use:");
|
||||||
|
candidates.forEach(System.err::println);
|
||||||
|
}
|
||||||
|
throw new FileNotFoundException("cannot locate 'cs/labs.jar'");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
fail(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPreferredSize(new Dimension(600, 150));
|
||||||
|
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
setResizable(false);
|
||||||
|
pack();
|
||||||
|
|
||||||
|
setLocationRelativeTo(null);
|
||||||
|
|
||||||
|
setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showDialog(String message, String buttonLabel, Runnable onClick) {
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
messageArea.setText(message);
|
||||||
|
buttonArea.removeAll();
|
||||||
|
buttonArea.repaint();
|
||||||
|
JButton b = new JButton(buttonLabel);
|
||||||
|
b.addActionListener(e -> {
|
||||||
|
b.setEnabled(false);
|
||||||
|
onClick.run();
|
||||||
|
});
|
||||||
|
buttonArea.add(b);
|
||||||
|
getRootPane().setDefaultButton(b);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fail(Throwable t) {
|
||||||
|
t.printStackTrace(System.err);
|
||||||
|
showDialog("Error: " + t.getClass().getSimpleName() + " (see console)",
|
||||||
|
"Quit", () -> System.exit(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void check(Path labsJar) {
|
||||||
|
try {
|
||||||
|
messageArea.setText("Checking...");
|
||||||
|
|
||||||
|
Path tempDir = labsJar.getParent().resolve("archive");
|
||||||
|
Files.createDirectories(tempDir);
|
||||||
|
|
||||||
|
Path downloadJar = Files.createTempFile(tempDir, ".download-", ".jar");
|
||||||
|
downloadJar.toFile().deleteOnExit();
|
||||||
|
|
||||||
|
HttpRequest req = HttpRequest.newBuilder(DOWNLOAD_URI).build();
|
||||||
|
HttpClient.newHttpClient()
|
||||||
|
.sendAsync(req, BodyHandlers.ofFile(downloadJar))
|
||||||
|
.thenAccept(response -> {
|
||||||
|
try {
|
||||||
|
int status = response.statusCode();
|
||||||
|
if (status != HttpURLConnection.HTTP_OK) {
|
||||||
|
showDialog("Unexpected status code: " + status,
|
||||||
|
"Quit", () -> System.exit(1));
|
||||||
|
} else if (Arrays.equals(Files.readAllBytes(labsJar), Files.readAllBytes(downloadJar))) { // same content
|
||||||
|
showDialog("No update available: you are using the latest version (" + getJarVersion(labsJar) + ")",
|
||||||
|
"OK", () -> System.exit(0));
|
||||||
|
} else if (!getCourseVersion(downloadJar).equals("fall 2024")) {
|
||||||
|
showDialog("Cannot update: latest update requires repo from " + getCourseVersion(downloadJar),
|
||||||
|
"OK", () -> System.exit(0));
|
||||||
|
} else {
|
||||||
|
showDialog("Update available: " + getJarVersion(downloadJar),
|
||||||
|
"Update now", () -> updateLabsJar(labsJar, downloadJar, tempDir));
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
fail(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (IOException e) {
|
||||||
|
fail(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLabsJar(Path labsJar, Path downloadJar, Path tempDir) {
|
||||||
|
try {
|
||||||
|
Path tempFile = Files.createTempFile(tempDir, "labs_jar_", ".old");
|
||||||
|
Files.move(labsJar, tempFile, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
Files.move(downloadJar, labsJar, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
showDialog("Success: you are now using the latest version!",
|
||||||
|
"OK", () -> System.exit(0));
|
||||||
|
} catch (IOException e) {
|
||||||
|
fail(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getCourseVersion(Path jar) {
|
||||||
|
try (JarFile f = new JarFile(jar.toFile())) {
|
||||||
|
Attributes a = f.getManifest().getAttributes("common");
|
||||||
|
return (a != null) ? a.getValue(Attributes.Name.SPECIFICATION_VERSION) : "unknown";
|
||||||
|
} catch (IOException e) {
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getJarVersion(Path jar) {
|
||||||
|
try (JarFile f = new JarFile(jar.toFile())) {
|
||||||
|
Attributes a = f.getManifest().getAttributes("common");
|
||||||
|
return (a != null) ? a.getValue(Attributes.Name.IMPLEMENTATION_VERSION) : "unknown";
|
||||||
|
} catch (IOException e) {
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
|
||||||
|
SwingUtilities.invokeLater(UpdateLabCode::new);
|
||||||
|
}
|
||||||
|
}
|
42
edaf85.code-workspace
Normal file
42
edaf85.code-workspace
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": "cs",
|
||||||
|
"name": "CS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "clock",
|
||||||
|
"name": "1. Alarm Clock"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "lift",
|
||||||
|
"name": "2. Passenger Lift"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "wash",
|
||||||
|
"name": "3. Washing Machine"
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"editor.insertSpaces": true,
|
||||||
|
"java.project.referencedLibraries": [
|
||||||
|
"../cs/labs.jar",
|
||||||
|
"../cs/junit/junit-platform-console-standalone-1.9.2.jar"
|
||||||
|
],
|
||||||
|
"files.exclude": {
|
||||||
|
"archive": true,
|
||||||
|
"bin": true,
|
||||||
|
".project": true,
|
||||||
|
".settings": true,
|
||||||
|
".classpath": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extensions": {
|
||||||
|
"recommendations": [
|
||||||
|
"redhat.java",
|
||||||
|
"vscjava.vscode-java-pack",
|
||||||
|
"vscjava.vscode-java-debug",
|
||||||
|
"vscjava.vscode-java-test",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
11
lift/.classpath
Normal file
11
lift/.classpath
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="module" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="lib" path="/cs/labs.jar"/>
|
||||||
|
<classpathentry kind="output" path="bin"/>
|
||||||
|
</classpath>
|
28
lift/.project
Normal file
28
lift/.project
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>2. Passenger lift</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
<filteredResources>
|
||||||
|
<filter>
|
||||||
|
<id>1678721711435</id>
|
||||||
|
<name></name>
|
||||||
|
<type>30</type>
|
||||||
|
<matcher>
|
||||||
|
<id>org.eclipse.core.resources.regexFilterMatcher</id>
|
||||||
|
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
|
||||||
|
</matcher>
|
||||||
|
</filter>
|
||||||
|
</filteredResources>
|
||||||
|
</projectDescription>
|
2
lift/.settings/org.eclipse.core.resources.prefs
Normal file
2
lift/.settings/org.eclipse.core.resources.prefs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding/<project>=UTF-8
|
30
lift/src/OnePersonRidesLift.java
Normal file
30
lift/src/OnePersonRidesLift.java
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
|
||||||
|
import lift.LiftView;
|
||||||
|
import lift.Passenger;
|
||||||
|
|
||||||
|
public class OnePersonRidesLift {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
final int NBR_FLOORS = 7, MAX_PASSENGERS = 4;
|
||||||
|
|
||||||
|
LiftView view = new LiftView(NBR_FLOORS, MAX_PASSENGERS);
|
||||||
|
Passenger pass = view.createPassenger();
|
||||||
|
int fromFloor = pass.getStartFloor();
|
||||||
|
int toFloor = pass.getDestinationFloor();
|
||||||
|
|
||||||
|
pass.begin(); // walk in (from left)
|
||||||
|
if (fromFloor != 0) {
|
||||||
|
view.moveLift(0, fromFloor);
|
||||||
|
}
|
||||||
|
view.openDoors(fromFloor);
|
||||||
|
pass.enterLift(); // step inside
|
||||||
|
|
||||||
|
view.closeDoors();
|
||||||
|
view.moveLift(fromFloor, toFloor); // ride lift
|
||||||
|
view.openDoors(toFloor);
|
||||||
|
|
||||||
|
pass.exitLift(); // leave lift
|
||||||
|
pass.end(); // walk out (to the right)
|
||||||
|
}
|
||||||
|
}
|
21
lift/src/lift/Passenger.java
Normal file
21
lift/src/lift/Passenger.java
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package lift;
|
||||||
|
|
||||||
|
public interface Passenger {
|
||||||
|
/** @return the floor the passenger starts at */
|
||||||
|
int getStartFloor();
|
||||||
|
|
||||||
|
/** @return the floor the passenger is going to */
|
||||||
|
int getDestinationFloor();
|
||||||
|
|
||||||
|
/** First, delay for 0..45 seconds. Then animate the passenger's walk, on the entry floor, to the lift. */
|
||||||
|
void begin();
|
||||||
|
|
||||||
|
/** Animate the passenger's walk from the entry floor into the lift. */
|
||||||
|
void enterLift();
|
||||||
|
|
||||||
|
/** Animate the passenger's walk out of the lift, to the exit floor. */
|
||||||
|
void exitLift();
|
||||||
|
|
||||||
|
/** Animate the passenger's walk, on the exit floor, out of view. */
|
||||||
|
void end();
|
||||||
|
}
|
12
wash/.classpath
Normal file
12
wash/.classpath
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="module" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="lib" path="/cs/labs.jar"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
|
||||||
|
<classpathentry kind="output" path="bin"/>
|
||||||
|
</classpath>
|
28
wash/.project
Normal file
28
wash/.project
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>3. Washing machine</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
<filteredResources>
|
||||||
|
<filter>
|
||||||
|
<id>1678721711437</id>
|
||||||
|
<name></name>
|
||||||
|
<type>30</type>
|
||||||
|
<matcher>
|
||||||
|
<id>org.eclipse.core.resources.regexFilterMatcher</id>
|
||||||
|
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
|
||||||
|
</matcher>
|
||||||
|
</filter>
|
||||||
|
</filteredResources>
|
||||||
|
</projectDescription>
|
2
wash/.settings/org.eclipse.core.resources.prefs
Normal file
2
wash/.settings/org.eclipse.core.resources.prefs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding/<project>=UTF-8
|
25
wash/src/actor/ActorThread.java
Normal file
25
wash/src/actor/ActorThread.java
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package actor;
|
||||||
|
|
||||||
|
public abstract class ActorThread<M> extends Thread {
|
||||||
|
|
||||||
|
// TODO: one suitable attribute here
|
||||||
|
|
||||||
|
/** Called by another thread, to send a message to this thread. */
|
||||||
|
public void send(M message) {
|
||||||
|
// TODO: implement this method (one or a few lines)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the first message in the queue, or blocks if none available. */
|
||||||
|
protected M receive() throws InterruptedException {
|
||||||
|
// TODO: implement this method (one or a few lines)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the first message in the queue, or blocks up to 'timeout'
|
||||||
|
milliseconds if none available. Returns null if no message is obtained
|
||||||
|
within 'timeout' milliseconds. */
|
||||||
|
protected M receiveWithTimeout(long timeout) throws InterruptedException {
|
||||||
|
// TODO: implement this method (one or a few lines)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
334
wash/src/actor/test/ActorThreadTest.java
Normal file
334
wash/src/actor/test/ActorThreadTest.java
Normal file
|
@ -0,0 +1,334 @@
|
||||||
|
package actor.test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.DelayQueue;
|
||||||
|
import java.util.concurrent.PriorityBlockingQueue;
|
||||||
|
import java.util.concurrent.SynchronousQueue;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
|
||||||
|
import org.junit.jupiter.api.Order;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.TestMethodOrder;
|
||||||
|
|
||||||
|
import actor.ActorThread;
|
||||||
|
|
||||||
|
@TestMethodOrder(OrderAnnotation.class)
|
||||||
|
class ActorThreadTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(1)
|
||||||
|
void testBidirectional() throws InterruptedException {
|
||||||
|
checkMainPrints(ExampleBidirectional::main,
|
||||||
|
"ClientThread sending request\n" +
|
||||||
|
"request received by FibonacciThread\n" +
|
||||||
|
"received result fib(14) = 377\n" +
|
||||||
|
"FibonacciThread terminated\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(2)
|
||||||
|
void testProducerConsumer() throws InterruptedException {
|
||||||
|
checkMainPrints(ExampleProducerConsumer::main,
|
||||||
|
"consumer eagerly awaiting messages...\n" +
|
||||||
|
"received [ole]\n" +
|
||||||
|
"received [dole]\n" +
|
||||||
|
"received [doff]\n" +
|
||||||
|
"all done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(3)
|
||||||
|
void testMessagingWithTimeout() throws InterruptedException {
|
||||||
|
checkMainPrints(ExampleMessagingWithTimeout::main,
|
||||||
|
"consumer eagerly awaiting messages...\n" +
|
||||||
|
"received [ole]\n" +
|
||||||
|
"received [dole]\n" +
|
||||||
|
"received [null]\n" +
|
||||||
|
"received [doff]\n" +
|
||||||
|
"all done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(4)
|
||||||
|
void testMessagingWithTimeoutButMessagesWaiting() throws InterruptedException {
|
||||||
|
checkMainPrints(ExampleReceiveWithTimeoutKeepsMessagesInOrder::main,
|
||||||
|
"consumer eagerly awaiting messages...\n" +
|
||||||
|
"received [yxi]\n" +
|
||||||
|
"received [kaxi]\n" +
|
||||||
|
"received [kolme]\n" +
|
||||||
|
"received [null]\n" +
|
||||||
|
"all done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that ActorThread has one single attribute
|
||||||
|
* of type BlockingQueue (or a type implementing BlockingQueue),
|
||||||
|
* and that the chosen queue type does not have a capacity limit
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@Order(5)
|
||||||
|
void testActorThreadUsesBlockingQueue() throws IllegalArgumentException, IllegalAccessException {
|
||||||
|
Field[] attributes = ActorThread.class.getDeclaredFields();
|
||||||
|
assertEquals(1, attributes.length, "expected one single attribute (BlockingQueue)");
|
||||||
|
|
||||||
|
if (attributes.length == 1) {
|
||||||
|
Field queueAttribute = attributes[0];
|
||||||
|
Class<?> attributeType = queueAttribute.getType();
|
||||||
|
assertTrue(BlockingQueue.class.isAssignableFrom(attributeType), "expected BlockingQueue attribute");
|
||||||
|
|
||||||
|
// inspect the actual attribute value
|
||||||
|
ActorThread<?> t = new ActorThread<>() { /* concrete subclass to abstract superclass */ };
|
||||||
|
queueAttribute.setAccessible(true);
|
||||||
|
Object value = queueAttribute.get(t);
|
||||||
|
assertFalse(value instanceof ArrayBlockingQueue, "ArrayBlockingQueue has a limited capacity: can lead to deadlock when used for message queues. Consider LinkedBlockingQueue");
|
||||||
|
assertFalse(value instanceof DelayQueue, "DelayQueue introduces additional delays: inappropriate for message queues. Consider LinkedBlockingQueue");
|
||||||
|
assertFalse(value instanceof PriorityBlockingQueue, "PriorityBlockingQueue reorders elements: inappropriate for message queues. Consider LinkedBlockingQueue");
|
||||||
|
assertFalse(value instanceof SynchronousQueue, "SynchronousQueue has a limited capacity: can lead to deadlock when used for message queues. Consider LinkedBlockingQueue");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that ActorThread methods are not synchronized
|
||||||
|
* (they shouldn't be, as BlockingQueues are thread-safe)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@Order(6)
|
||||||
|
void testActorThreadNotUsingSynchronized() {
|
||||||
|
Method[] methods = ActorThread.class.getDeclaredMethods();
|
||||||
|
assertEquals(3, methods.length, "expected three methods: send, receive, receiveWithTimeout");
|
||||||
|
|
||||||
|
for (Method m : methods) {
|
||||||
|
assertFalse(Modifier.isSynchronized(m.getModifiers()), "method " + m.getName() + " is synchronized, but shouldn't be");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that ActorThread method send() is not declared
|
||||||
|
* 'throws InterruptedException'
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@Order(7)
|
||||||
|
void testSendNotDeclaredThrows() {
|
||||||
|
for (Method m : ActorThread.class.getDeclaredMethods()) {
|
||||||
|
if ("send".equals(m.getName())) {
|
||||||
|
Type[] exceptionsThrown = m.getExceptionTypes();
|
||||||
|
if (exceptionsThrown.length != 0) {
|
||||||
|
String[] exceptions = Stream.of(exceptionsThrown)
|
||||||
|
.map(t -> {
|
||||||
|
String n = t.getTypeName();
|
||||||
|
int dot = n.lastIndexOf('.');
|
||||||
|
return (dot >= 0) ? n.substring(dot + 1) : n;
|
||||||
|
}).toArray(String[]::new);
|
||||||
|
String typeString = String.join(", ", exceptions);
|
||||||
|
|
||||||
|
System.err.println("** ERROR:");
|
||||||
|
System.err.println("**");
|
||||||
|
System.err.println("** Method 'send()' was declared 'throws " + typeString + "'.");
|
||||||
|
System.err.println("** This method should not throw any exceptions.\n");
|
||||||
|
System.err.println("** HINT:");
|
||||||
|
System.err.println("**");
|
||||||
|
System.err.println("** Don't use the BlockingQueue method put(). Use add() or offer() instead.");
|
||||||
|
System.err.println("** Then remove 'throws " + typeString + "' from method 'send'.");
|
||||||
|
}
|
||||||
|
assertEquals(0, exceptionsThrown.length, "method 'send' should not throw any exceptions");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fail("no method 'send' found in ActorThread");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that ActorThread methods receive() and receiveWithTimeout()
|
||||||
|
* are declared 'throws InterruptedException'
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@Order(8)
|
||||||
|
void testReceivesDeclaredThrows() {
|
||||||
|
int k = 0;
|
||||||
|
for (Method m : ActorThread.class.getDeclaredMethods()) {
|
||||||
|
String name = m.getName();
|
||||||
|
if ("receive".equals(name) || "receiveWithTimeout".equals(name)) {
|
||||||
|
Type[] exceptionsThrown = m.getExceptionTypes();
|
||||||
|
Set<String> typeNames = Stream.of(exceptionsThrown).map(Type::getTypeName).collect(Collectors.toSet());
|
||||||
|
boolean throwsInterruptedException = typeNames.contains(InterruptedException.class.getTypeName());
|
||||||
|
assertTrue(throwsInterruptedException, "method '" + name + "' should be declared 'throws InterruptedException'");
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(2, k, "missing method 'receive' and/or 'receiveWithTimeout'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(9)
|
||||||
|
void testReceiveBlocks() throws InterruptedException {
|
||||||
|
AtomicBoolean interruptionHandledCorrectly = new AtomicBoolean(false);
|
||||||
|
ActorThread<?> blocker = new ActorThread<>() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
receive();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// interruption expected: check
|
||||||
|
// InterruptedException handled correctly
|
||||||
|
interruptionHandledCorrectly.set(true);
|
||||||
|
} catch (Throwable unexpected) {
|
||||||
|
fail("unexpected exception", unexpected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
blocker.start();
|
||||||
|
expectThreadState(blocker, Thread.State.WAITING);
|
||||||
|
blocker.interrupt();
|
||||||
|
expectThreadState(blocker, Thread.State.TERMINATED);
|
||||||
|
|
||||||
|
assertTrue(interruptionHandledCorrectly.get(), "receive must not catch InterruptedException");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(10)
|
||||||
|
void testReceiveWithTimeoutBlocks() throws InterruptedException {
|
||||||
|
AtomicBoolean interruptionHandledCorrectly = new AtomicBoolean(false);
|
||||||
|
ActorThread<?> blocker = new ActorThread<>() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
receiveWithTimeout(60 * 60 * 1000); // one hour
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// interruption expected: check
|
||||||
|
// InterruptedException handled correctly
|
||||||
|
interruptionHandledCorrectly.set(true);
|
||||||
|
} catch (Throwable unexpected) {
|
||||||
|
fail("unexpected exception", unexpected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
blocker.start();
|
||||||
|
expectThreadState(blocker, Thread.State.TIMED_WAITING);
|
||||||
|
blocker.interrupt();
|
||||||
|
expectThreadState(blocker, Thread.State.TERMINATED);
|
||||||
|
|
||||||
|
assertTrue(interruptionHandledCorrectly.get(), "receiveWithTimeout must not catch InterruptedException");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(11)
|
||||||
|
void testReceiveWithTimeoutDelay() throws InterruptedException {
|
||||||
|
List<Long> measurements = new ArrayList<>();
|
||||||
|
ActorThread<?> delayed = new ActorThread<>() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
long t0 = System.currentTimeMillis();
|
||||||
|
receiveWithTimeout(300);
|
||||||
|
long t1 = System.currentTimeMillis();
|
||||||
|
receiveWithTimeout(100);
|
||||||
|
long t2 = System.currentTimeMillis();
|
||||||
|
receiveWithTimeout(200);
|
||||||
|
long t3 = System.currentTimeMillis();
|
||||||
|
measurements.add(t1 - t0);
|
||||||
|
measurements.add(t2 - t1);
|
||||||
|
measurements.add(t3 - t2);
|
||||||
|
} catch (Throwable unexpected) {
|
||||||
|
fail("unexpected exception", unexpected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
delayed.start();
|
||||||
|
delayed.join();
|
||||||
|
|
||||||
|
assertEquals(3, measurements.size());
|
||||||
|
|
||||||
|
// allow 50ms additional delay: huge overkill
|
||||||
|
assertTrue(measurements.get(0) >= 300 && measurements.get(0) < 350);
|
||||||
|
assertTrue(measurements.get(1) >= 100 && measurements.get(1) < 150);
|
||||||
|
assertTrue(measurements.get(2) >= 200 && measurements.get(2) < 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(12)
|
||||||
|
void testFinal() {
|
||||||
|
Field[] attributes = ActorThread.class.getDeclaredFields();
|
||||||
|
|
||||||
|
// previous tests check we have exactly one appropriate attribute
|
||||||
|
if (attributes.length >= 1) {
|
||||||
|
Field queueAttribute = attributes[0];
|
||||||
|
int mod = queueAttribute.getModifiers();
|
||||||
|
assertTrue(Modifier.isFinal(mod), "reference attribute should be final");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(13)
|
||||||
|
void testPrivate() {
|
||||||
|
Field[] attributes = ActorThread.class.getDeclaredFields();
|
||||||
|
|
||||||
|
// previous tests check we have exactly one appropriate attribute
|
||||||
|
if (attributes.length >= 1) {
|
||||||
|
Field queueAttribute = attributes[0];
|
||||||
|
int mod = queueAttribute.getModifiers();
|
||||||
|
assertTrue(Modifier.isPrivate(mod), "queue attribute should be private");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Helper interface for making lambdas, for a main function that throws InterruptedException */
|
||||||
|
private interface InterruptibleMain {
|
||||||
|
void invoke(String... args) throws InterruptedException;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Helper method: run a main method in another class, and check the printed output. */
|
||||||
|
private void checkMainPrints(InterruptibleMain main, String expectedOutput) throws InterruptedException {
|
||||||
|
PrintStream sysout = System.out;
|
||||||
|
OutputStream bos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
System.setOut(new PrintStream(bos, true));
|
||||||
|
main.invoke();
|
||||||
|
} finally {
|
||||||
|
System.setOut(sysout);
|
||||||
|
|
||||||
|
// make sure line feeds are always represented as "\n",
|
||||||
|
// regardless of what the system uses
|
||||||
|
String actualOutput = bos.toString().replace(System.getProperty("line.separator"), "\n");
|
||||||
|
assertEquals(expectedOutput, actualOutput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Helper method: check thread t is in the given state. */
|
||||||
|
private static void expectThreadState(Thread t, Thread.State expectedState) throws InterruptedException {
|
||||||
|
// there is no way to wait for a thread state change:
|
||||||
|
// we have to resort to polling
|
||||||
|
|
||||||
|
long t0 = System.currentTimeMillis(), now = t0;
|
||||||
|
Thread.State actualState = t.getState();
|
||||||
|
while (actualState != expectedState
|
||||||
|
&& actualState != Thread.State.TERMINATED
|
||||||
|
&& now < t0 + 1000) // give up after one second
|
||||||
|
{
|
||||||
|
Thread.sleep(20);
|
||||||
|
actualState = t.getState();
|
||||||
|
now = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
assertEquals(expectedState, actualState);
|
||||||
|
}
|
||||||
|
}
|
67
wash/src/actor/test/ExampleBidirectional.java
Normal file
67
wash/src/actor/test/ExampleBidirectional.java
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
package actor.test;
|
||||||
|
|
||||||
|
import actor.ActorThread;
|
||||||
|
|
||||||
|
public class ExampleBidirectional {
|
||||||
|
|
||||||
|
private ActorThread<Integer>
|
||||||
|
ct = new ClientThread(),
|
||||||
|
ft = new FibonacciThread();
|
||||||
|
|
||||||
|
class ClientThread extends ActorThread<Integer> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
System.out.println("ClientThread sending request");
|
||||||
|
ft.send(14);
|
||||||
|
int reply = receive();
|
||||||
|
System.out.println("received result fib(14) = " + reply);
|
||||||
|
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// not expected to happen
|
||||||
|
throw new Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FibonacciThread extends ActorThread<Integer> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
int n = receive();
|
||||||
|
System.out.println("request received by FibonacciThread");
|
||||||
|
|
||||||
|
int f2 = 0;
|
||||||
|
int f1 = 1;
|
||||||
|
for (int k = 2; k <= n; k++) {
|
||||||
|
int s = f2 + f1;
|
||||||
|
f2 = f1;
|
||||||
|
f1 = s;
|
||||||
|
Thread.sleep(100);
|
||||||
|
}
|
||||||
|
ct.send(f1);
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
System.out.println("FibonacciThread terminated");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) throws InterruptedException {
|
||||||
|
ExampleBidirectional app = new ExampleBidirectional();
|
||||||
|
|
||||||
|
app.ct.start();
|
||||||
|
app.ft.start();
|
||||||
|
|
||||||
|
app.ct.join();
|
||||||
|
app.ft.interrupt();
|
||||||
|
app.ft.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
57
wash/src/actor/test/ExampleMessagingWithTimeout.java
Normal file
57
wash/src/actor/test/ExampleMessagingWithTimeout.java
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package actor.test;
|
||||||
|
|
||||||
|
import actor.ActorThread;
|
||||||
|
|
||||||
|
public class ExampleMessagingWithTimeout {
|
||||||
|
|
||||||
|
private Producer p = new Producer();
|
||||||
|
private Consumer c = new Consumer();
|
||||||
|
|
||||||
|
class Producer extends Thread {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Thread.sleep(300);
|
||||||
|
c.send("ole");
|
||||||
|
Thread.sleep(300);
|
||||||
|
c.send("dole");
|
||||||
|
Thread.sleep(1000);
|
||||||
|
c.send("doff");
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// not expected to happen
|
||||||
|
throw new Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Consumer extends ActorThread<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
System.out.println("consumer eagerly awaiting messages...");
|
||||||
|
for (int k = 0; k < 3; k++) {
|
||||||
|
String s = receiveWithTimeout(500);
|
||||||
|
System.out.println("received [" + s + "]");
|
||||||
|
}
|
||||||
|
String s = receiveWithTimeout(2000);
|
||||||
|
System.out.println("received [" + s + "]");
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// not expected to happen
|
||||||
|
throw new Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws InterruptedException {
|
||||||
|
ExampleMessagingWithTimeout app = new ExampleMessagingWithTimeout();
|
||||||
|
|
||||||
|
app.p.start();
|
||||||
|
app.c.start();
|
||||||
|
|
||||||
|
app.p.join();
|
||||||
|
app.c.join();
|
||||||
|
System.out.println("all done");
|
||||||
|
}
|
||||||
|
}
|
55
wash/src/actor/test/ExampleProducerConsumer.java
Normal file
55
wash/src/actor/test/ExampleProducerConsumer.java
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
package actor.test;
|
||||||
|
|
||||||
|
import actor.ActorThread;
|
||||||
|
|
||||||
|
public class ExampleProducerConsumer {
|
||||||
|
|
||||||
|
private Producer p = new Producer();
|
||||||
|
private Consumer c = new Consumer();
|
||||||
|
|
||||||
|
class Producer extends Thread {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Thread.sleep(300);
|
||||||
|
c.send("ole");
|
||||||
|
Thread.sleep(300);
|
||||||
|
c.send("dole");
|
||||||
|
Thread.sleep(300);
|
||||||
|
c.send("doff");
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// not expected to happen
|
||||||
|
throw new Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Consumer extends ActorThread<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
System.out.println("consumer eagerly awaiting messages...");
|
||||||
|
for (int k = 0; k < 3; k++) {
|
||||||
|
String s = receive();
|
||||||
|
System.out.println("received [" + s + "]");
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// not expected to happen
|
||||||
|
throw new Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws InterruptedException {
|
||||||
|
ExampleProducerConsumer app = new ExampleProducerConsumer();
|
||||||
|
|
||||||
|
app.p.start();
|
||||||
|
app.c.start();
|
||||||
|
|
||||||
|
app.p.join();
|
||||||
|
app.c.join();
|
||||||
|
System.out.println("all done");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package actor.test;
|
||||||
|
|
||||||
|
import actor.ActorThread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test was introduced to detect possible errors in the implementation
|
||||||
|
* of ActorThread.receiveWithTimeout().
|
||||||
|
*
|
||||||
|
* So if this test is the only one that fails, review your
|
||||||
|
* receiveWithTimeout() implementation. It must not remove more than one
|
||||||
|
* message from the queue.
|
||||||
|
*/
|
||||||
|
public class ExampleReceiveWithTimeoutKeepsMessagesInOrder {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws InterruptedException {
|
||||||
|
|
||||||
|
ActorThread<String> c = new ActorThread<>() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
System.out.println("consumer eagerly awaiting messages...");
|
||||||
|
for (int k = 0; k < 4; k++) {
|
||||||
|
String s = receiveWithTimeout(100);
|
||||||
|
System.out.println("received [" + s + "]");
|
||||||
|
}
|
||||||
|
} catch (InterruptedException unexpected) {
|
||||||
|
throw new Error(unexpected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
c.send("yxi");
|
||||||
|
c.send("kaxi");
|
||||||
|
c.send("kolme");
|
||||||
|
|
||||||
|
c.start();
|
||||||
|
c.join();
|
||||||
|
System.out.println("all done");
|
||||||
|
}
|
||||||
|
}
|
7
wash/src/wash/control/Settings.java
Normal file
7
wash/src/wash/control/Settings.java
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package wash.control;
|
||||||
|
|
||||||
|
interface Settings {
|
||||||
|
// simulation speed-up factor: 50 means the simulation is 50 times faster than
|
||||||
|
// real time. Modify this as you wish.
|
||||||
|
int SPEEDUP = 50;
|
||||||
|
}
|
42
wash/src/wash/control/SpinController.java
Normal file
42
wash/src/wash/control/SpinController.java
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package wash.control;
|
||||||
|
|
||||||
|
import actor.ActorThread;
|
||||||
|
import wash.io.WashingIO;
|
||||||
|
import wash.io.WashingIO.Spin;
|
||||||
|
|
||||||
|
public class SpinController extends ActorThread<WashingMessage> {
|
||||||
|
|
||||||
|
// TODO: add attributes
|
||||||
|
|
||||||
|
public SpinController(WashingIO io) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
// this is to demonstrate how to control the barrel spin:
|
||||||
|
// io.setSpinMode(Spin.IDLE);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// ... TODO ...
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// wait for up to a (simulated) minute for a WashingMessage
|
||||||
|
WashingMessage m = receiveWithTimeout(60000 / Settings.SPEEDUP);
|
||||||
|
|
||||||
|
// if m is null, it means a minute passed and no message was received
|
||||||
|
if (m != null) {
|
||||||
|
System.out.println("got " + m);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... TODO ...
|
||||||
|
}
|
||||||
|
} catch (InterruptedException unexpected) {
|
||||||
|
// we don't expect this thread to be interrupted,
|
||||||
|
// so throw an error if it happens anyway
|
||||||
|
throw new Error(unexpected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
wash/src/wash/control/TemperatureController.java
Normal file
18
wash/src/wash/control/TemperatureController.java
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package wash.control;
|
||||||
|
|
||||||
|
import actor.ActorThread;
|
||||||
|
import wash.io.WashingIO;
|
||||||
|
|
||||||
|
public class TemperatureController extends ActorThread<WashingMessage> {
|
||||||
|
|
||||||
|
// TODO: add attributes
|
||||||
|
|
||||||
|
public TemperatureController(WashingIO io) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
31
wash/src/wash/control/Wash.java
Normal file
31
wash/src/wash/control/Wash.java
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package wash.control;
|
||||||
|
|
||||||
|
import actor.ActorThread;
|
||||||
|
import wash.io.WashingIO;
|
||||||
|
import wash.simulation.WashingSimulator;
|
||||||
|
|
||||||
|
public class Wash {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws InterruptedException {
|
||||||
|
WashingSimulator sim = new WashingSimulator(Settings.SPEEDUP);
|
||||||
|
|
||||||
|
WashingIO io = sim.startSimulation();
|
||||||
|
|
||||||
|
ActorThread<WashingMessage> temp = new TemperatureController(io);
|
||||||
|
ActorThread<WashingMessage> water = new WaterController(io);
|
||||||
|
ActorThread<WashingMessage> spin = new SpinController(io);
|
||||||
|
|
||||||
|
temp.start();
|
||||||
|
water.start();
|
||||||
|
spin.start();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
int n = io.awaitButton();
|
||||||
|
System.out.println("user selected program " + n);
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// if the user presses buttons 1-3, start a washing program
|
||||||
|
// if the user presses button 0, and a program has been started, stop it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
30
wash/src/wash/control/WashingMessage.java
Normal file
30
wash/src/wash/control/WashingMessage.java
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package wash.control;
|
||||||
|
|
||||||
|
import actor.ActorThread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class used for messaging
|
||||||
|
* - from washing programs to spin controller (SPIN_xxx)
|
||||||
|
* - from washing programs to temperature controller (TEMP_xxx)
|
||||||
|
* - from washing programs to water controller (WATER_xxx)
|
||||||
|
* - from controllers to washing programs (ACKNOWLEDGMENT)
|
||||||
|
*
|
||||||
|
* @param sender the thread that sent the message
|
||||||
|
* @param order an order, such as SPIN_FAST or WATER_DRAIN
|
||||||
|
*/
|
||||||
|
public record WashingMessage(ActorThread<WashingMessage> sender, Order order) {
|
||||||
|
|
||||||
|
// possible values for the 'order' attribute
|
||||||
|
public enum Order {
|
||||||
|
SPIN_OFF,
|
||||||
|
SPIN_SLOW,
|
||||||
|
SPIN_FAST,
|
||||||
|
TEMP_IDLE,
|
||||||
|
TEMP_SET_40,
|
||||||
|
TEMP_SET_60,
|
||||||
|
WATER_IDLE,
|
||||||
|
WATER_FILL,
|
||||||
|
WATER_DRAIN,
|
||||||
|
ACKNOWLEDGMENT
|
||||||
|
}
|
||||||
|
}
|
79
wash/src/wash/control/WashingProgram3.java
Normal file
79
wash/src/wash/control/WashingProgram3.java
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
package wash.control;
|
||||||
|
|
||||||
|
import actor.ActorThread;
|
||||||
|
import wash.io.WashingIO;
|
||||||
|
|
||||||
|
import static wash.control.WashingMessage.Order.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Program 3 for washing machine. This also serves as an example of how washing
|
||||||
|
* programs can be structured.
|
||||||
|
*
|
||||||
|
* This short program stops all regulation of temperature and water levels,
|
||||||
|
* stops the barrel from spinning, and drains the machine of water.
|
||||||
|
*
|
||||||
|
* It can be used after an emergency stop (program 0) or a power failure.
|
||||||
|
*/
|
||||||
|
public class WashingProgram3 extends ActorThread<WashingMessage> {
|
||||||
|
|
||||||
|
private WashingIO io;
|
||||||
|
private ActorThread<WashingMessage> temp;
|
||||||
|
private ActorThread<WashingMessage> water;
|
||||||
|
private ActorThread<WashingMessage> spin;
|
||||||
|
|
||||||
|
public WashingProgram3(WashingIO io,
|
||||||
|
ActorThread<WashingMessage> temp,
|
||||||
|
ActorThread<WashingMessage> water,
|
||||||
|
ActorThread<WashingMessage> spin)
|
||||||
|
{
|
||||||
|
this.io = io;
|
||||||
|
this.temp = temp;
|
||||||
|
this.water = water;
|
||||||
|
this.spin = spin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
System.out.println("washing program 3 started");
|
||||||
|
|
||||||
|
// Switch off heating
|
||||||
|
temp.send(new WashingMessage(this, TEMP_IDLE));
|
||||||
|
|
||||||
|
// Wait for temperature controller to acknowledge
|
||||||
|
WashingMessage ack1 = receive();
|
||||||
|
System.out.println("got " + ack1);
|
||||||
|
|
||||||
|
// Drain barrel, which may take some time. To ensure the barrel
|
||||||
|
// is drained before we continue, an acknowledgment is required.
|
||||||
|
water.send(new WashingMessage(this, WATER_DRAIN));
|
||||||
|
WashingMessage ack2 = receive(); // wait for acknowledgment
|
||||||
|
System.out.println("got " + ack2);
|
||||||
|
|
||||||
|
// Now that the barrel is drained, we can turn off water regulation.
|
||||||
|
water.send(new WashingMessage(this, WATER_IDLE));
|
||||||
|
WashingMessage ack3 = receive(); // wait for acknowledgment
|
||||||
|
System.out.println("got " + ack3);
|
||||||
|
|
||||||
|
// Switch off spin. We expect an acknowledgment, to ensure
|
||||||
|
// the hatch isn't opened while the barrel is spinning.
|
||||||
|
spin.send(new WashingMessage(this, SPIN_OFF));
|
||||||
|
WashingMessage ack4 = receive(); // wait for acknowledgment
|
||||||
|
System.out.println("got " + ack4);
|
||||||
|
|
||||||
|
// Unlock hatch
|
||||||
|
io.lock(false);
|
||||||
|
|
||||||
|
System.out.println("washing program 3 finished");
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
|
||||||
|
// If we end up here, it means the program was interrupt()'ed:
|
||||||
|
// set all controllers to idle
|
||||||
|
|
||||||
|
temp.send(new WashingMessage(this, TEMP_IDLE));
|
||||||
|
water.send(new WashingMessage(this, WATER_IDLE));
|
||||||
|
spin.send(new WashingMessage(this, SPIN_OFF));
|
||||||
|
System.out.println("washing program terminated");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
wash/src/wash/control/WaterController.java
Normal file
18
wash/src/wash/control/WaterController.java
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package wash.control;
|
||||||
|
|
||||||
|
import actor.ActorThread;
|
||||||
|
import wash.io.WashingIO;
|
||||||
|
|
||||||
|
public class WaterController extends ActorThread<WashingMessage> {
|
||||||
|
|
||||||
|
// TODO: add attributes
|
||||||
|
|
||||||
|
public WaterController(WashingIO io) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
32
wash/src/wash/io/WashingIO.java
Normal file
32
wash/src/wash/io/WashingIO.java
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package wash.io;
|
||||||
|
|
||||||
|
/** Input/Output (IO) for our washing machine */
|
||||||
|
public interface WashingIO {
|
||||||
|
|
||||||
|
/** @return water level, in range 0..20 liters */
|
||||||
|
double getWaterLevel();
|
||||||
|
|
||||||
|
/** @return temperature, in degrees Celsius */
|
||||||
|
double getTemperature();
|
||||||
|
|
||||||
|
/** Blocks until a program button (0, 1, 2, 3) is pressed */
|
||||||
|
int awaitButton() throws InterruptedException;
|
||||||
|
|
||||||
|
/** Turn heating element on (true) or off (false) */
|
||||||
|
void heat(boolean on);
|
||||||
|
|
||||||
|
/** Set inlet valve to open (true) or closed (false) */
|
||||||
|
void fill(boolean on);
|
||||||
|
|
||||||
|
/** Turn drain pump on (true) or off (false) */
|
||||||
|
void drain(boolean on);
|
||||||
|
|
||||||
|
/** Set hatch to locked (true) or unlocked (false) */
|
||||||
|
void lock(boolean locked);
|
||||||
|
|
||||||
|
/** @param mode one of Spin.IDLE, Spin.LEFT, Spin.RIGHT, Spin.FAST */
|
||||||
|
void setSpinMode(Spin mode);
|
||||||
|
|
||||||
|
/** Values for setSpinMode */
|
||||||
|
enum Spin { IDLE, LEFT, RIGHT, FAST };
|
||||||
|
}
|
Loading…
Reference in a new issue