Add coding tasks for OSGi, III. Service Tracker (#113)

Sample implementations of the [third part of the OSGi Coding Tasks](http://docs.openhab.org/developers/prerequisites/osgitasks.html#iii-service-tracker).

Modified org.openhab.training.electricity.provider bundle.

Also-by: Elena Miovska <elena.miovska@musala.com> (github: emiovska)
Signed-off-by: Kiril Atanasov <kiril.atanasov@musala.com> (github: kirilAtan)
pull/126/head
Kiril Atanasov 2016-11-02 11:37:08 +02:00 committed by Thomas Dietrich
parent d014fa70d1
commit 958388d6c5
25 changed files with 857 additions and 6 deletions

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.training.electricity.battery</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,13 @@
Manifest-Version: 1.0
Bundle-Name: Battery
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-Vendor: openHAB.org
Bundle-Version: 1.0.0.qualifier
Bundle-ManifestVersion: 2
Bundle-License: http://www.eclipse.org/legal/epl-v10.html
Bundle-SymbolicName: org.openhab.training.electricity.battery
Import-Package: org.openhab.training.electricity.battery,
org.openhab.training.electricity.provider,
org.osgi.framework
Export-Package: org.openhab.training.electricity.battery
Bundle-Activator: org.openhab.training.electricity.battery.BatteryActivator

View File

@ -0,0 +1,28 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<title>About</title>
</head>
<body lang="EN-US">
<h2>About This Content</h2>
<p>&lt;<em>September 15, 2014</em>&gt;</p>
<h3>License</h3>
<p>The openHAB community makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
indicated below, the Content is provided to you under the terms and conditions of the
Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
<p>If you did not receive this Content directly from the openHAB community, the Content is
being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
apply to your use of any object code in the Content. Check the Redistributor's license that was
provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
indicated below, the terms and conditions of the EPL still apply to any source code in the Content
and such source code may be obtained at <a href="http://www.openhab.org/">openhab.org</a>.</p>
</body>
</html>

View File

@ -0,0 +1,4 @@
source.. = src/main/java
output.. = target/classes/
bin.includes = META-INF/,\
.

View File

@ -0,0 +1,48 @@
/**
* Copyright (c) 2014-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.training.electricity.battery;
import org.openhab.training.electricity.provider.ElectricityProvider;
import org.openhab.training.electricity.provider.ElectricityProviderType;
/**
* The class {@link Battery} is an {@link ElectricityProvider} which has a
* limited amount of energy it can provide.
*
* @author Kiril Atanasov - Initial contribution
*/
public class Battery implements ElectricityProvider {
/** The amount of energy the Battery can provide */
protected int energyAmount = 20;
/**
* Checks if the {@link Battery} has enough energy to power a consumer,
* based on its consumption. The method is synchronized in case there are
* multiple consumers using the {@link Battery} service at the same time.
*
* @param value
* the amount of energy that is being demanded.
* @return true if the {@link Battery} can provide the demanded amount of
* energy, false otherwise.
*/
@Override
public synchronized boolean provide(int value) {
if (value >= 0 && value <= energyAmount) {
energyAmount -= value;
return true;
}
return false;
}
@Override
public ElectricityProviderType getType() {
return ElectricityProviderType.BATTERY;
}
}

View File

@ -0,0 +1,36 @@
/**
* Copyright (c) 2014-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.training.electricity.battery;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.openhab.training.electricity.provider.ElectricityProvider;
/**
* The class {@link BatteryActivator} activates this bundle.
*
* @author Kiril Atanasov - Initial contribution
*/
public class BatteryActivator implements BundleActivator {
private ServiceRegistration<Battery> batteryServiceRegistration;
@SuppressWarnings("unchecked")
@Override
public void start(BundleContext context) throws Exception {
batteryServiceRegistration = (ServiceRegistration<Battery>) context
.registerService(ElectricityProvider.class.getName(), new Battery(), null);
}
@Override
public void stop(BundleContext context) throws Exception {
batteryServiceRegistration.unregister();
}
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.training.electricity.dynamicconsumer</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,11 @@
Manifest-Version: 1.0
Bundle-Name: Dynamic Consumer
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-Vendor: openHAB.org
Bundle-Version: 1.0.0.qualifier
Bundle-ManifestVersion: 2
Bundle-License: http://www.eclipse.org/legal/epl-v10.html
Bundle-SymbolicName: org.openhab.training.electricity.dynamicconsumer
Import-Package: org.openhab.training.electricity.dynamicconsumer,
org.openhab.training.electricity.provider
Export-Package: org.openhab.training.electricity.dynamicconsumer

View File

@ -0,0 +1,28 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<title>About</title>
</head>
<body lang="EN-US">
<h2>About This Content</h2>
<p>&lt;<em>September 15, 2014</em>&gt;</p>
<h3>License</h3>
<p>The openHAB community makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
indicated below, the Content is provided to you under the terms and conditions of the
Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
<p>If you did not receive this Content directly from the openHAB community, the Content is
being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
apply to your use of any object code in the Content. Check the Redistributor's license that was
provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
indicated below, the terms and conditions of the EPL still apply to any source code in the Content
and such source code may be obtained at <a href="http://www.openhab.org/">openhab.org</a>.</p>
</body>
</html>

View File

@ -0,0 +1,4 @@
source.. = src/main/java/
output.. = target/classes/
bin.includes = META-INF/,\
.

View File

@ -0,0 +1,38 @@
/**
* Copyright (c) 2014-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.training.electricity.dynamicconsumer;
import org.openhab.training.electricity.provider.ElectricityProvider;
/**
* This interface is used for managing multiple {@link ElectricityProvider}s.
*
* @author Kiril Atanasov - Initial contribution
*/
public interface DynamicConsumer {
/**
* Adds an {@link ElectricityProvider} to the consumer's available
* providers.
*
* @param electricityProvider
* the specific {@link ElectricityProvider} that will be added.
*/
void providerAdded(ElectricityProvider electricityProvider);
/**
* Removes an {@link ElectricityProvider} from the consumer's available
* providers.
*
* @param electricityProvider
* the specific {@link ElectricityProvider} that will be removed.
*/
void providerRemoved(ElectricityProvider electricityProvider);
}

View File

@ -1,4 +1,3 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
@ -12,18 +11,18 @@
<p>&lt;<em>September 15, 2014</em>&gt;</p>
<h3>License</h3>
<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
<p>The openHAB community makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
indicated below, the Content is provided to you under the terms and conditions of the
Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
<p>If you did not receive this Content directly from the openHAB community, the Content is
being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
apply to your use of any object code in the Content. Check the Redistributor's license that was
provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
indicated below, the terms and conditions of the EPL still apply to any source code in the Content
and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
and such source code may be obtained at <a href="http://www.openhab.org/">openhab.org</a>.</p>
</body>
</html>

View File

@ -17,8 +17,8 @@ package org.openhab.training.electricity.provider;
public interface ElectricityProvider {
/**
* Indicates whether an {@link ElectricityProvider} can provide enough energy
* to a consumer.
* Indicates whether an {@link ElectricityProvider} can provide enough
* energy to a consumer.
*
* @param value
* the energy consumption of the consumer
@ -26,4 +26,12 @@ public interface ElectricityProvider {
* requirements, false otherwise
*/
boolean provide(int value);
/**
* Returns the type of the {@link ElectricityProvider} from
* {@link ElectricityProviderType}.
*
* @return the type of the {@link ElectricityProvider}.
*/
ElectricityProviderType getType();
}

View File

@ -0,0 +1,20 @@
/**
* Copyright (c) 2014-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.training.electricity.provider;
/**
* The type of the {@link ElectricityProvider}.
*
* @author Kiril Atanasov - Initial contribution
*/
public enum ElectricityProviderType {
HOME_NETWORK,
BATTERY,
SOLAR_SOURCE;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.training.electricity.tv</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,17 @@
Manifest-Version: 1.0
Bundle-Name: TV
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-Vendor: openHAB.org
Bundle-Version: 1.0.0.qualifier
Bundle-ManifestVersion: 2
Bundle-License: http://www.eclipse.org/legal/epl-v10.html
Bundle-SymbolicName: org.openhab.training.electricity.tv
Import-Package: org.openhab.training.electricity.battery,
org.openhab.training.electricity.consumer,
org.openhab.training.electricity.dynamicconsumer,
org.openhab.training.electricity.homenetwork,
org.openhab.training.electricity.provider,
org.osgi.framework,
org.osgi.util.tracker,
org.slf4j
Bundle-Activator: org.openhab.training.electricity.tv.TVActivator

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.pde.ui.EquinoxLauncher">
<booleanAttribute key="append.args" value="true"/>
<booleanAttribute key="automaticAdd" value="false"/>
<booleanAttribute key="automaticValidate" value="false"/>
<stringAttribute key="bootstrap" value=""/>
<stringAttribute key="checked" value="[NONE]"/>
<booleanAttribute key="clearConfig" value="false"/>
<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/TVRuntimeEvnironment"/>
<booleanAttribute key="default" value="true"/>
<booleanAttribute key="default_auto_start" value="true"/>
<intAttribute key="default_start_level" value="4"/>
<booleanAttribute key="includeOptional" value="false"/>
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Declipse.ignoreApp=true -Dosgi.noShutdown=true"/>
<stringAttribute key="pde.version" value="3.3"/>
<booleanAttribute key="show_selected_only" value="true"/>
<stringAttribute key="target_bundles" value="ch.qos.logback.classic@default:default,ch.qos.logback.core@default:default,ch.qos.logback.slf4j@default:false,org.apache.felix.gogo.command@default:default,org.apache.felix.gogo.runtime@default:default,org.apache.felix.gogo.shell@default:default,org.eclipse.equinox.console@default:default,org.eclipse.osgi.services@default:default,org.eclipse.osgi@-1:true,org.slf4j.api@default:default"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
<booleanAttribute key="useDefaultConfigArea" value="true"/>
<stringAttribute key="workspace_bundles" value="org.openhab.training.electricity.battery@default:default,org.openhab.training.electricity.consumer@default:default,org.openhab.training.electricity.dynamicconsumer@default:default,org.openhab.training.electricity.homenetwork@default:default,org.openhab.training.electricity.provider@default:default,org.openhab.training.electricity.tv@5:default"/>
</launchConfiguration>

View File

@ -0,0 +1,28 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<title>About</title>
</head>
<body lang="EN-US">
<h2>About This Content</h2>
<p>&lt;<em>September 15, 2014</em>&gt;</p>
<h3>License</h3>
<p>The openHAB community makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
indicated below, the Content is provided to you under the terms and conditions of the
Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
<p>If you did not receive this Content directly from the openHAB community, the Content is
being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
apply to your use of any object code in the Content. Check the Redistributor's license that was
provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
indicated below, the terms and conditions of the EPL still apply to any source code in the Content
and such source code may be obtained at <a href="http://www.openhab.org/">openhab.org</a>.</p>
</body>
</html>

View File

@ -0,0 +1,4 @@
source.. = src/main/java
output.. = target/classes
bin.includes = META-INF/,\
.

View File

@ -0,0 +1,281 @@
/**
* Copyright (c) 2014-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.training.electricity.tv;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.openhab.training.electricity.battery.Battery;
import org.openhab.training.electricity.consumer.ElectricityConsumer;
import org.openhab.training.electricity.dynamicconsumer.DynamicConsumer;
import org.openhab.training.electricity.homenetwork.HomeElectricityNetwork;
import org.openhab.training.electricity.provider.ElectricityProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The class {@link TV} can use two types of {@link ElectricityProvider}s
* -{@link HomeElectricityNetwork} and {@link Battery}, but only one of them at
* a time. The {@link HomeElectricityNetwork} is with priority. If there is no
* {@link ElectricityProvider} or the available {@link ElectricityProvider}(s)
* can't provide enough charge, the {@link TV} waits(doesn't print anything),
* but it is active - if a provider, which could supply enough energy is added
* the TV starts broadcasting.
* <p>
* Due to the specifics of the {@link ElectricityProvider} interface all the
* available {@link ElectricityProvider}s will be divided into two groups:
* <ul>
* <li>{@link #usableProviders} is where all the new providers will be put, the
* {@link TV} will use them until they are depleted, after which they will be
* moved to the other group.</li>
* <li>{@link #depletedProviders} is where all the providers that can't provide
* enough power to run the {@link TV} are.</li>
* </ul>
* This separation into two groups is made, so that the {@link TV} can keep
* track of which providers are usable and which are depleted. This is very
* important when choosing which {@link ElectricityProvider} to use.
* <p>
* In {@link #usableProviders} the {@link ElectricityProvider}s will be ordered
* based on their rating. Their rating will be determined in the
* {@link ProvidersComparatorForTV#getRating(ElectricityProvider)}, based on the
* type of the {@link ElectricityProvider}. If one provider has higher rating
* than another, it must be used before the second.
*
* @author Kiril Atanasov - Initial contribution
* @author Elena Miovska - sorting the {@link ElectricityProvider}s based on
* their type, and picking the {@link #currentElectricityProvider} among
* them.
*/
public class TV implements ElectricityConsumer, DynamicConsumer {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* Holds all the {@link ElectricityProvider}s the TV can use. They will be
* ordered according to the criteria specified in
* {@link ProvidersComparatorForTV}.
*/
protected PriorityQueue<ElectricityProvider> usableProviders = new PriorityQueue<>(new ProvidersComparatorForTV());
/** A list of the depleted {@link ElectricityProvider}s */
protected List<ElectricityProvider> depletedProviders = new ArrayList<>();
/**
* The {@link ElectricityProvider} that the TV uses at the moment, the one
* it will try to utilize.
*/
protected ElectricityProvider currentElectricityProvider;
/** The power consumption of the TV */
protected final int TV_CONSUMPTION = 10;
/** The time (in seconds) the TV waits before trying to use a provider */
protected final int BROADCASTING_PERIOD = 5;
/**
* {@inheritDoc}
* <p>
* After the {@link ElectricityProvider} has been added we check if the
* {@link #currentElectricityProvider} should be changed.
*/
@Override
public synchronized void providerAdded(ElectricityProvider electricityProvider) {
usableProviders.add(electricityProvider);
if (shouldTheCurrentProviderBeChanged(electricityProvider)) {
setCurrentProvider();
}
}
/**
* Determines if the {@link #currentElectricityProvider} should be changed,
* when adding a new {@link ElectricityProvider}.
*
* @param electricityProvider
* the {@link ElectricityProvider} that has been added.
* @return true if {@link #currentElectricityProvider} should be changed,
* false otherwise.
*/
private boolean shouldTheCurrentProviderBeChanged(ElectricityProvider electricityProvider) {
return currentElectricityProvider == null || ProvidersComparatorForTV
.isTheSecondProviderWithHigherPriority(currentElectricityProvider, electricityProvider);
}
/**
* {@inheritDoc}
* <p>
* If the electricityProvider, which is being removed is also the
* {@link #currentElectricityProvider} then the
* {@link #currentElectricityProvider} is set to {@code null}.
*
* @param electricityProvider
* the {@link ElectricityProvider} service which has been removed
*/
@Override
public synchronized void providerRemoved(ElectricityProvider electricityProvider) {
if (usableProviders.contains(electricityProvider)) {
usableProviders.remove(electricityProvider);
} else {
depletedProviders.remove(electricityProvider);
}
if (currentElectricityProvider == electricityProvider) {
removeCurrentElectricityProvider();
}
}
/**
* Changes the {@link #currentElectricityProvider} to another
* {@link #currentElectricityProvider}.
*/
protected void removeCurrentElectricityProvider() {
logger.info("provider {} is no longer available. ", currentElectricityProvider.toString());
setCurrentProvider();
}
/**
* The {@link #currentElectricityProvider} is set to be the head of the
* {@link #usableProviders} or {@code null} if there are no usable
* providers.
*/
public void setCurrentProvider() {
setCurrentProvider(usableProviders.peek());
}
@Override
public void setCurrentProvider(ElectricityProvider electricityProvider) {
currentElectricityProvider = electricityProvider;
}
/**
* {@inheritDoc}
* <p>
* The TV starts the scheduler. The scheduler starts running and will run
* until given the shutdownNow() command.
*/
@Override
public void start() {
scheduler.scheduleAtFixedRate(broadcastingAction, 0, BROADCASTING_PERIOD, TimeUnit.SECONDS);
}
/**
* {@inheritDoc}
* <p>
* The TV invokes the {@link #scheduler}'s stop method, otherwise the
* {@link #scheduler} will continue running even after the {@link TV} bundle
* is stopped.
*/
@Override
public void stop() {
scheduler.shutdownNow();
}
@Override
public List<ElectricityProvider> getAllAvailableProviders() {
return new ArrayList<ElectricityProvider>(usableProviders);
}
/**
* It is not advised to start a Thread on its own. That's why we are using a
* ScheduledExecutorService. It will be able to run only one Thread at a
* time.
*/
protected final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
/**
* {@link #broadcastingAction} checks if there are any
* {@link ElectricityProvider}s in {@link #usableProviders}. If so this
* means the {@link TV} could be able to broadcast. If an
* {@link ElectricityProvider} gets depleted it is moved to the
* {@link #depletedProviders} and a message is being displayed.
*/
protected Runnable broadcastingAction = new Runnable() {
@Override
public void run() {
synchronized (TV.this) {
if (!usableProviders.isEmpty()) {
if (currentElectricityProvider.provide(TV_CONSUMPTION)) {
actWhenPowered();
} else {
actWhenNotPowered();
moveProviderFromUsableToDepleted(currentElectricityProvider);
}
}
}
}
};
/** What will the {@link TV} do when it has enough power. */
protected void actWhenPowered() {
// Displaying a message which provider is in use.
logger.info("broadcasting on {}", currentElectricityProvider.getClass().getName());
}
/**
* What will the {@link TV} do when it has {@link ElectricityProvider} but
* not enough power.
*/
protected void actWhenNotPowered() {
// Displaying a message that the provider in use has been depleted.
logger.info("provider {} is depleted. ", currentElectricityProvider.toString());
}
/**
* Moves an {@link ElectricityProvider} from {@link #usableProviders} to
* {@link #depletedProviders}. If the {@link #usableProviders} is empty it
* displays a notification message.
*
* @param electricityProvider
* the {@link ElectricityProvider} that must be moved.
*/
protected void moveProviderFromUsableToDepleted(ElectricityProvider electricityProvider) {
usableProviders.remove(electricityProvider);
depletedProviders.add(electricityProvider);
if (usableProviders.isEmpty()) {
logger.info("There are no more usable providers");
} else {
setCurrentProvider();
}
}
@Override
public ElectricityProvider getCurrentElectricityProvider() {
return this.currentElectricityProvider;
}
}
/**
* This class will implement the logic by which the {@link ElectricityProvider}s
* will be arranged in {@link #usableProviders}.
*/
class ProvidersComparatorForTV implements Comparator<ElectricityProvider> {
@Override
public int compare(ElectricityProvider first, ElectricityProvider second) {
return getRating(second) - getRating(first);
}
public static boolean isTheSecondProviderWithHigherPriority(ElectricityProvider first, ElectricityProvider second) {
return getRating(first) - getRating(second) < 0;
}
public static int getRating(ElectricityProvider electricityProvider) {
switch (electricityProvider.getType()) {
case HOME_NETWORK:
return 1000;
case BATTERY:
return 500;
default:
return 0;
}
}
}

View File

@ -0,0 +1,69 @@
/**
* Copyright (c) 2014-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.training.electricity.tv;
import org.openhab.training.electricity.consumer.ElectricityConsumer;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
/**
* The class {@link TVActivator} is responsible for the activation of this
* bundle.
*
* @author Kiril Atanasov - Initial contribution
*/
public class TVActivator implements BundleActivator {
private TvPowerProviderTracker tracker;
private ServiceRegistration<TV> tvServiceRegistration;
/**
* {@inheritDoc}
* <p>
* Registers a TV and a TVServiceTracker service.
*/
@SuppressWarnings("unchecked")
@Override
public void start(BundleContext context) throws Exception {
// A TV instance. We could register a service with it
TV tv = new TV();
// Registering the TV Service
tvServiceRegistration = (ServiceRegistration<TV>) context.registerService(ElectricityConsumer.class.getName(),
tv, null);
/*
* we are linking the reference to an actual {@link TVServiceTracker}
* object
*/
tracker = new TvPowerProviderTracker(context, tv);
tracker.open();
// The TV is starting to consume power from the providers
tracker.getTV().start();
}
/**
* {@inheritDoc}
* <p>
* Stops and unregisters the TVServiceTracker service. Unregistering the TV
* Service.
*/
@Override
public void stop(BundleContext context) throws Exception {
tracker.getTV().stop();
tvServiceRegistration.unregister();
tracker.close();
}
}

View File

@ -0,0 +1,84 @@
/**
* Copyright (c) 2014-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.training.electricity.tv;
import org.openhab.training.electricity.provider.ElectricityProvider;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
/**
* The class {@link TvPowerProviderTracker} is tracking all the services which
* implement the {@link ElectricityProvider} interface.
*
* @author Kiril Atanasov - Initial contribution
*/
public class TvPowerProviderTracker extends ServiceTracker<Object, Object> {
/**
* The ServiceTracker will add/remove/modify providers of the {@link #tv}.
*/
private TV tv = null;
/**
* This constructor sets ServiceTracker to track all the services using the
* {@link ElectricityProvider} interface.
* <p>
* All the services, which don't implement the {@link ElectricityProvider}
* interface or aren't registered won't be tracked by
* {@link TvPowerProviderTracker}.
*
* @param context
* the bundle context, usually injected by the BundleActivator
* @param tv
* the {@link TV} object to which the ServiceTracker will add,
* remove or modify {@link ElectricityProvider}(s).
*/
public TvPowerProviderTracker(BundleContext context, TV tv) {
super(context, ElectricityProvider.class.getName(), null);
this.tv = tv;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public Object addingService(ServiceReference reference) {
ElectricityProvider provider = (ElectricityProvider) context.getService(reference);
tv.providerAdded(provider);
/*
* This method must return the service object for the specified
* ServiceReference and in our case that is provider.
*/
return provider;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void removedService(ServiceReference reference, Object service) {
ElectricityProvider provider = (ElectricityProvider) context.getService(reference);
tv.providerRemoved(provider);
context.ungetService(reference);
}
/**
* {@inheritDoc}
* <p>
* This service will be called when the modified functions of a tracked
* service is called. The modified function is defined with declarative
* services.
*/
@SuppressWarnings("rawtypes")
@Override
public void modifiedService(ServiceReference reference, Object service) {
/* This method will not be used in this implementation */
}
public TV getTV() {
return this.tv;
}
}