Selaa lähdekoodia

Merge pull request #30 from mrbig/f/dynamic_implementation_loader

Made implementation classes configurable from the respective properties file
Marc Mültin 6 vuotta sitten
vanhempi
commit
0bf6d51748

+ 7 - 0
RISE-V2G-EVCC/EVCCConfig.properties

@@ -83,6 +83,13 @@ authentication.mode =
 # - DC_unique
 energy.transfermode.requested = AC_three_phase_core
 
+#
+# Implementation classes
+#---------------------------------------------
+# If you want to replace the implementation then set the following value
+# to the name of your class
+# When omitted default dummy implementation will be used
+implementation.evcc.controller = com.v2gclarity.risev2g.evcc.evController.DummyEVController
 
 # XML representation of messages
 #-------------------------------

+ 2 - 2
RISE-V2G-EVCC/src/main/java/com/v2gclarity/risev2g/evcc/evController/DummyEVController.java

@@ -57,8 +57,7 @@ public class DummyEVController implements IACEVController, IDCEVController {
 	private CPStates cpState;
 	private int chargingLoopCounter;
 	
-	public DummyEVController(V2GCommunicationSessionEVCC commSessionContext) {
-		setCommSessionContext(commSessionContext);
+	public DummyEVController() {
 		setCPState(CPStates.STATE_B); // should be signaled before ISO/IEC 15118 stack initializes
 		setChargingLoopCounter((short) 0);
 	}
@@ -187,6 +186,7 @@ public class DummyEVController implements IACEVController, IDCEVController {
 		return commSessionContext;
 	}
 
+	@Override
 	public void setCommSessionContext(V2GCommunicationSessionEVCC commSessionContext) {
 		this.commSessionContext = commSessionContext;
 	}

+ 8 - 0
RISE-V2G-EVCC/src/main/java/com/v2gclarity/risev2g/evcc/evController/IEVController.java

@@ -23,6 +23,7 @@
  *******************************************************************************/
 package com.v2gclarity.risev2g.evcc.evController;
 
+import com.v2gclarity.risev2g.evcc.session.V2GCommunicationSessionEVCC;
 import com.v2gclarity.risev2g.shared.enumerations.CPStates;
 import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.ChargingProfileType;
 import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.EnergyTransferModeType;
@@ -31,6 +32,13 @@ import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.PaymentOptionType;
 
 public interface IEVController {
 
+	/**
+	 * Provides a reference to the current communication session for
+	 * this controller instance.
+	 * @param commSessionContext The active communication session
+	 */
+	public void setCommSessionContext(V2GCommunicationSessionEVCC commSessionContext);
+	
 	/**
 	 * Returns the user-chosen payment method, either external identification means (EIM) such as an 
 	 * RFID card or via Plug-and-Charge (PnC)

+ 50 - 0
RISE-V2G-EVCC/src/main/java/com/v2gclarity/risev2g/evcc/misc/EVCCImplementationFactory.java

@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * The MIT License (MIT)
+ *
+ * Copyright 2017 Dr.-Ing. Marc Mültin (V2G Clarity)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *******************************************************************************/
+package com.v2gclarity.risev2g.evcc.misc;
+
+import com.v2gclarity.risev2g.evcc.evController.DummyEVController;
+import com.v2gclarity.risev2g.evcc.evController.IEVController;
+import com.v2gclarity.risev2g.evcc.session.V2GCommunicationSessionEVCC;
+import com.v2gclarity.risev2g.shared.misc.V2GImplementationFactory;
+
+/**
+ * Implementation factory for the EVCC controller
+ *
+ */
+public class EVCCImplementationFactory extends V2GImplementationFactory {
+
+	/**
+	 * Creates the controller for the EVCC application
+	 * @param commSessionContext the session the backend will be connected to 
+	 * @return
+	 */
+	public static IEVController createEVController(V2GCommunicationSessionEVCC commSessionContext) {
+		IEVController instance = buildFromProperties("implementation.evcc.controller", IEVController.class);
+		if (instance == null) {
+			instance = new DummyEVController();
+		}
+		instance.setCommSessionContext(commSessionContext);
+		return instance;
+	}
+}

+ 2 - 2
RISE-V2G-EVCC/src/main/java/com/v2gclarity/risev2g/evcc/session/V2GCommunicationSessionEVCC.java

@@ -28,8 +28,8 @@ import java.util.List;
 import java.util.Observable;
 import java.util.Observer;
 
-import com.v2gclarity.risev2g.evcc.evController.DummyEVController;
 import com.v2gclarity.risev2g.evcc.evController.IEVController;
+import com.v2gclarity.risev2g.evcc.misc.EVCCImplementationFactory;
 import com.v2gclarity.risev2g.evcc.states.WaitForAuthorizationRes;
 import com.v2gclarity.risev2g.evcc.states.WaitForCableCheckRes;
 import com.v2gclarity.risev2g.evcc.states.WaitForCertificateInstallationRes;
@@ -137,7 +137,7 @@ public class V2GCommunicationSessionEVCC extends V2GCommunicationSession impleme
 		
 		// configure which EV controller implementation to use
 		// TODO the EV controller needs to run as a separate Thread (to receive notifications from the EV and to avoid blocking calls to the controller)
-		setEvController(new DummyEVController(this));
+		setEvController(EVCCImplementationFactory.createEVController(this));
 		
 		/*
 		 * Is needed for measuring the time span between transition to state B (plug-in) and receipt 

+ 9 - 0
RISE-V2G-SECC/SECCConfig.properties

@@ -76,6 +76,15 @@ authentication.modes.supported = Contract, ExternalPayment
 # - false
 environment.private = false
 
+#
+# Implementation classes
+#---------------------------------------------
+# If you want to replace the implementations then set the following values
+# to the name of your classes
+# When omitted default dummy implementations will be used
+implementation.secc.backend = com.v2gclarity.risev2g.secc.backend.DummyBackendInterface
+implementation.secc.acevsecontroller = com.v2gclarity.risev2g.secc.evseController.DummyACEVSEController
+implementation.secc.dcevsecontroller = com.v2gclarity.risev2g.secc.evseController.DummyDCEVSEController
 
 # XML representation of messages
 #-------------------------------

+ 2 - 2
RISE-V2G-SECC/src/main/java/com/v2gclarity/risev2g/secc/backend/DummyBackendInterface.java

@@ -59,8 +59,7 @@ public class DummyBackendInterface implements IBackendInterface {
 		this.moSubCA2PrivateKey = moSubCA2PrivateKey;
 	}
 
-	public DummyBackendInterface(V2GCommunicationSessionSECC commSessionContext) {
-		setCommSessionContext(commSessionContext);
+	public DummyBackendInterface() {
 		
 		/*
 		 * In order to reduce timing problems with handling ChargeParameterDiscoveryReq, reading the private key of the MO Sub-CA2
@@ -313,6 +312,7 @@ public class DummyBackendInterface implements IBackendInterface {
 		return commSessionContext;
 	}
 
+	@Override
 	public void setCommSessionContext(V2GCommunicationSessionSECC commSessionContext) {
 		this.commSessionContext = commSessionContext;
 	}

+ 8 - 0
RISE-V2G-SECC/src/main/java/com/v2gclarity/risev2g/secc/backend/IBackendInterface.java

@@ -27,11 +27,19 @@ import java.security.cert.X509Certificate;
 import java.security.interfaces.ECPrivateKey;
 import java.util.HashMap;
 
+import com.v2gclarity.risev2g.secc.session.V2GCommunicationSessionSECC;
 import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.CertificateChainType;
 import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.SAScheduleListType;
 
 public interface IBackendInterface {
 
+	/**
+	 * Provides a reference to the current communication session for
+	 * this backend interface.
+	 * @param commSessionContext The active communication session
+	 */
+	public void setCommSessionContext(V2GCommunicationSessionSECC commSessionContext);
+	
 	/**
 	 * Provides a list of schedules coming from a secondary actor (SAScheduleList) with pMax values
 	 * and optional tariff incentives which shall influence the charging behaviour of the EV.

+ 2 - 2
RISE-V2G-SECC/src/main/java/com/v2gclarity/risev2g/secc/evseController/DummyACEVSEController.java

@@ -42,8 +42,7 @@ public class DummyACEVSEController implements IACEVSEController {
 	@SuppressWarnings("unused")
 	private V2GCommunicationSessionSECC commSessionContext;
 	
-	public DummyACEVSEController(V2GCommunicationSessionSECC commSessionContext) {
-		setCommSessionContext(commSessionContext);
+	public DummyACEVSEController() {
 	}
 	
 	@Override
@@ -87,6 +86,7 @@ public class DummyACEVSEController implements IACEVSEController {
 	}
 
 	
+	@Override
 	public void setCommSessionContext(V2GCommunicationSessionSECC commSessionContext) {
 		this.commSessionContext = commSessionContext;
 	}

+ 2 - 2
RISE-V2G-SECC/src/main/java/com/v2gclarity/risev2g/secc/evseController/DummyDCEVSEController.java

@@ -51,8 +51,7 @@ public class DummyDCEVSEController implements IDCEVSEController {
 	private PhysicalValueType maximumEVPowerLimit;
 	private IsolationLevelType isolationLevel;
 	
-	public DummyDCEVSEController(V2GCommunicationSessionSECC commSessionContext) {
-		setCommSessionContext(commSessionContext);
+	public DummyDCEVSEController() {
 		setIsolationLevel(IsolationLevelType.INVALID);
 	}
 	
@@ -85,6 +84,7 @@ public class DummyDCEVSEController implements IDCEVSEController {
 		return commSessionContext;
 	}
 
+	@Override
 	public void setCommSessionContext(V2GCommunicationSessionSECC commSessionContext) {
 		this.commSessionContext = commSessionContext;
 	}

+ 8 - 0
RISE-V2G-SECC/src/main/java/com/v2gclarity/risev2g/secc/evseController/IEVSEController.java

@@ -23,11 +23,19 @@
  *******************************************************************************/
 package com.v2gclarity.risev2g.secc.evseController;
 
+import com.v2gclarity.risev2g.secc.session.V2GCommunicationSessionSECC;
 import com.v2gclarity.risev2g.shared.v2gMessages.msgDef.MeterInfoType;
 
 
 public interface IEVSEController {
 
+	/**
+	 * Provides a reference to the current communication session for
+	 * this controller instance.
+	 * @param commSessionContext The active communication session
+	 */
+	public void setCommSessionContext(V2GCommunicationSessionSECC commSessionContext);
+	
 	/**
 	 * The EVSEID is formatted according to Annex H of ISO/IEC 15118 and consists of minimum 7, max 37
 	 * characters.

+ 84 - 0
RISE-V2G-SECC/src/main/java/com/v2gclarity/risev2g/secc/misc/SECCImplementationFactory.java

@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * The MIT License (MIT)
+ *
+ * Copyright 2017 Dr.-Ing. Marc Mültin (V2G Clarity)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *******************************************************************************/
+package com.v2gclarity.risev2g.secc.misc;
+
+import com.v2gclarity.risev2g.secc.backend.DummyBackendInterface;
+import com.v2gclarity.risev2g.secc.backend.IBackendInterface;
+import com.v2gclarity.risev2g.secc.evseController.DummyACEVSEController;
+import com.v2gclarity.risev2g.secc.evseController.DummyDCEVSEController;
+import com.v2gclarity.risev2g.secc.evseController.IACEVSEController;
+import com.v2gclarity.risev2g.secc.evseController.IDCEVSEController;
+import com.v2gclarity.risev2g.secc.session.V2GCommunicationSessionSECC;
+import com.v2gclarity.risev2g.shared.misc.V2GImplementationFactory;
+
+/**
+ * Implementation factory for the SECC controllers and for the backend interface
+ *
+ */
+public class SECCImplementationFactory extends V2GImplementationFactory {
+
+	
+	/**
+	 * Creates the backend interface for the SECC application
+	 * @param commSessionContext the session the backend will be connected to 
+	 * @return
+	 */
+	public static IBackendInterface createBackendInterface(V2GCommunicationSessionSECC commSessionContext) {
+		IBackendInterface instance = buildFromProperties("implementation.secc.backend", IBackendInterface.class);
+		if (instance == null) {
+			instance = new DummyBackendInterface();
+		}
+		instance.setCommSessionContext(commSessionContext);
+		return instance;
+	}
+	
+	/**
+	 * Creates the AC EVSE controller for the SECC application
+	 * @param commSessionContext the session the backend will be connected to 
+	 * @return
+	 */
+	public static IACEVSEController createACEVSEController(V2GCommunicationSessionSECC commSessionContext) {
+		IACEVSEController instance = buildFromProperties("implementation.secc.acevsecontroller", IACEVSEController.class);
+		if (instance == null) {
+			instance = new DummyACEVSEController();
+		}
+		instance.setCommSessionContext(commSessionContext);
+		return instance;
+	}
+	
+	/**
+	 * Creates the DC EVSE controller for the SECC application
+	 * @param commSessionContext the session the backend will be connected to 
+	 * @return
+	 */
+	public static IDCEVSEController createDCEVSEController(V2GCommunicationSessionSECC commSessionContext) {
+		IDCEVSEController instance = buildFromProperties("implementation.secc.dcevsecontroller", IDCEVSEController.class);
+		if (instance == null) {
+			instance = new DummyDCEVSEController();
+		}
+		instance.setCommSessionContext(commSessionContext);
+		return instance;
+	}
+	
+}

+ 4 - 6
RISE-V2G-SECC/src/main/java/com/v2gclarity/risev2g/secc/session/V2GCommunicationSessionSECC.java

@@ -29,13 +29,11 @@ import java.util.Arrays;
 import java.util.Observable;
 import java.util.Observer;
 
-import com.v2gclarity.risev2g.secc.backend.DummyBackendInterface;
 import com.v2gclarity.risev2g.secc.backend.IBackendInterface;
-import com.v2gclarity.risev2g.secc.evseController.DummyACEVSEController;
-import com.v2gclarity.risev2g.secc.evseController.DummyDCEVSEController;
 import com.v2gclarity.risev2g.secc.evseController.IACEVSEController;
 import com.v2gclarity.risev2g.secc.evseController.IDCEVSEController;
 import com.v2gclarity.risev2g.secc.evseController.IEVSEController;
+import com.v2gclarity.risev2g.secc.misc.SECCImplementationFactory;
 import com.v2gclarity.risev2g.secc.states.ForkState;
 import com.v2gclarity.risev2g.secc.states.WaitForAuthorizationReq;
 import com.v2gclarity.risev2g.secc.states.WaitForCableCheckReq;
@@ -132,11 +130,11 @@ public class V2GCommunicationSessionSECC extends V2GCommunicationSession impleme
 		setCurrentState(getStartState());
 		
 		// Configure which EVSE controller implementation to use
-		setACEvseController(new DummyACEVSEController(this));
-		setDCEvseController(new DummyDCEVSEController(this));
+		setACEvseController(SECCImplementationFactory.createACEVSEController(this));
+		setDCEvseController(SECCImplementationFactory.createDCEVSEController(this));
 		
 		// Configures which backend interface implementation to use for retrieving SASchedules
-		setBackendInterface(new DummyBackendInterface(this));
+		setBackendInterface(SECCImplementationFactory.createBackendInterface(this));
 
 		// ACEVSE notification
 		setAcEVSEStatus(new ACEVSEStatusType());

+ 63 - 0
RISE-V2G-Shared/src/main/java/com/v2gclarity/risev2g/shared/misc/V2GImplementationFactory.java

@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * The MIT License (MIT)
+ *
+ * Copyright 2017 Dr.-Ing. Marc Mültin (V2G Clarity)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *******************************************************************************/
+package com.v2gclarity.risev2g.shared.misc;
+
+import com.v2gclarity.risev2g.shared.utils.MiscUtils;
+
+/**
+ * This class serves as the base for implementation factory
+ * classes used in the SE/EV projects
+ * It will look up and instantiate a class based on a
+ * configuration property
+ */
+abstract public class V2GImplementationFactory {
+
+	/**
+	 * Builds an object instance from the configuration properties
+	 * The configuration should hold the class of the instance that
+	 * will be built.
+	 * @param propertyName Name of the property that contains the fully qualified class name
+	 * @param cls Target class of the build instance
+	 * @return
+	 */
+	protected static <T> T buildFromProperties(String propertyName, Class<T> cls) {
+		try {
+			String className = MiscUtils.getV2gEntityConfig().getProperty(propertyName);
+			if (className == null) {
+				return null;
+			}
+			
+			Object instance = Class.forName(className).newInstance();
+			
+			if (!cls.isInstance(instance)) {
+				throw new Exception("Instantiated object does not match the expected type " + cls.getCanonicalName());
+			}
+			return cls.cast(instance);
+		} catch (Exception e) {
+			throw new RuntimeException("Could not instantiate implementations class for property " + propertyName, e);
+		}
+	}
+
+	
+}