diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/ICicsRegion.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/ICicsRegion.java index 74e26173a..58729c8a7 100644 --- a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/ICicsRegion.java +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/ICicsRegion.java @@ -52,6 +52,7 @@ public interface ICicsRegion { ICemt cemt() throws CicstsManagerException; ICeda ceda() throws CicstsManagerException; ICeci ceci() throws CicstsManagerException; + ITsqFactory getTsqFactory() throws CicstsManagerException; /** * Provides a CICS resource instance that can then be used to create a specific CICS resource diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/ITsq.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/ITsq.java new file mode 100644 index 000000000..f37fb42ab --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/ITsq.java @@ -0,0 +1,53 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package dev.galasa.cicsts; + +import javax.validation.constraints.NotNull; +public interface ITsq { + + /** + * Check the existence of a TSQ. + * @throws TsqException if there is a problem in checking the TSQ existence + * @return boolean based on if TSQ is existing or not + */ + public boolean exists() throws TsqException; + + /** + * Check if a TSQ is recoverable. + * @throws TsqException if there is a problem in checking if the TSQ is recoverable or not + * @return boolean based on if TSQ is recoverable or not + */ + public boolean isRecoverable() throws TsqException; + + /** + * Read Data from TSQ based on item number. + * @param item Item number of the TSQ to be read + * @return Data read from TSQ as String + * @throws TsqException if there is a problem in reading from the TSQ + */ + public String readQueue(int item) throws TsqException; + + /** + * Read next from TSQ. + * @return Data read from TSQ as String + * @throws TsqException if there is a problem in reading next from the TSQ + */ + public String readQueueNext() throws TsqException; + + /** + * Write data to TSQ. + * @param data The data to be written to the TSQ + * @throws TsqException if there is a problem in writing to the TSQ + */ + public void writeQueue(@NotNull String data) throws TsqException; + + /** + * Delete non-recoverable TSQ. + * @throws TsqException if there is a problem in deleting the TSQ + */ + public void deleteQueue() throws TsqException; + +} diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/ITsqFactory.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/ITsqFactory.java new file mode 100644 index 000000000..af836b625 --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/ITsqFactory.java @@ -0,0 +1,30 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package dev.galasa.cicsts; + +import javax.validation.constraints.NotNull; +public interface ITsqFactory { + + /** + * Create a new ITsq object with recoverable status + * @param queueName TSQ name + * @param isRecoverable true for recoverable and false for non-recoverable + * @return ITsq object. The existence of the ITsq object does not have any correlation to whether + * the queue actually exists underneath it. It is used to access or create the ITsq. + * @throws TsqException if there is a problem in creating the ITsq object + */ + public ITsq createQueue(@NotNull String queueName, boolean isRecoverable) throws TsqException; + + /** + * Create a new ITsq object without recoverable status. Default recoverable status is NonRecoverable + * @param queueName TSQ name + * @return ITsq object. The existence of the ITsq object does not have any correlation to whether + * the queue actually exists underneath it. It is used to access or create the ITsq. + * @throws TsqException if there is a problem in creating the ITsq object + */ + public ITsq createQueue(@NotNull String queueName) throws TsqException; + +} diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/TsqException.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/TsqException.java new file mode 100644 index 000000000..318ed5516 --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/TsqException.java @@ -0,0 +1,33 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package dev.galasa.cicsts; + +/* + * TsqException happens for errors in the TSQ manager methods. + */ +public class TsqException extends TsqManagerException { + private static final long serialVersionUID = 1L; + + public TsqException() { + } + + public TsqException(String message) { + super(message); + } + + public TsqException(Throwable cause) { + super(cause); + } + + public TsqException(String message, Throwable cause) { + super(message, cause); + } + + public TsqException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/TsqManagerException.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/TsqManagerException.java new file mode 100644 index 000000000..06edafb51 --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/TsqManagerException.java @@ -0,0 +1,34 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package dev.galasa.cicsts; + +/* + * TsqManagerException happens for errors in TSQ manager provisioning + */ +public class TsqManagerException extends CicstsManagerException { + private static final long serialVersionUID = 1L; + + public TsqManagerException() { + } + + public TsqManagerException(String message) { + super(message); + } + + public TsqManagerException(Throwable cause) { + super(cause); + } + + public TsqManagerException(String message, Throwable cause) { + super(message, cause); + } + + public TsqManagerException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/internal/CicstsManagerImpl.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/internal/CicstsManagerImpl.java index a91823646..e15abec64 100644 --- a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/internal/CicstsManagerImpl.java +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/internal/CicstsManagerImpl.java @@ -35,6 +35,7 @@ import dev.galasa.cicsts.spi.ICeciProvider; import dev.galasa.cicsts.spi.ICedaProvider; import dev.galasa.cicsts.spi.ICemtProvider; +import dev.galasa.cicsts.spi.ITsqProvider; import dev.galasa.cicsts.spi.ICicsRegionLogonProvider; import dev.galasa.cicsts.spi.ICicsRegionProvisioned; import dev.galasa.cicsts.spi.ICicsRegionProvisioner; @@ -80,6 +81,7 @@ public class CicstsManagerImpl extends AbstractManager implements ICicstsManager private ICeciProvider ceciProvider; private ICedaProvider cedaProvider; private ICemtProvider cemtProvider; + private ITsqProvider tsqProvider; private ICicsResourceProvider cicsResourceProvider; @Override @@ -361,6 +363,11 @@ public void registerCedaProvider(@NotNull ICedaProvider cedaProvider) { this.cedaProvider = cedaProvider; } + @Override + public void registerTsqProvider(@NotNull ITsqProvider tsqProvider) { + this.tsqProvider = tsqProvider; + } + @Override public void registerCemtProvider(@NotNull ICemtProvider cemtProvider) { this.cemtProvider = cemtProvider; @@ -390,6 +397,16 @@ public ICedaProvider getCedaProvider() throws CicstsManagerException { return this.cedaProvider; } + + @Override + @NotNull + public ITsqProvider getTsqProvider() throws CicstsManagerException { + if (this.tsqProvider == null) { + throw new CicstsManagerException("No TSQ provider has been registered"); + } + + return this.tsqProvider; + } @Override @NotNull diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/internal/properties/ExtraBundles.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/internal/properties/ExtraBundles.java index 80212006f..5dc2b4421 100644 --- a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/internal/properties/ExtraBundles.java +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/internal/properties/ExtraBundles.java @@ -1,8 +1,8 @@ -/* - * Copyright contributors to the Galasa project - * - * SPDX-License-Identifier: EPL-2.0 - */ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ package dev.galasa.cicsts.internal.properties; import java.util.ArrayList; @@ -42,6 +42,7 @@ public static List get() throws CicstsManagerException { list.add("dev.galasa.cicsts.ceci.manager"); list.add("dev.galasa.cicsts.ceda.manager"); list.add("dev.galasa.cicsts.cemt.manager"); + list.add("dev.galasa.cicsts.tsq.manager"); list.add("dev.galasa.cicsts.resource.manager"); list.add("dev.galasa.zosliberty.manager"); list.add("dev.galasa.textscan.manager"); diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/spi/BaseCicsImpl.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/spi/BaseCicsImpl.java index b94673d6f..3e7f90844 100644 --- a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/spi/BaseCicsImpl.java +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/spi/BaseCicsImpl.java @@ -1,14 +1,15 @@ -/* - * Copyright contributors to the Galasa project - * - * SPDX-License-Identifier: EPL-2.0 - */ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ package dev.galasa.cicsts.spi; import dev.galasa.cicsts.CicstsManagerException; import dev.galasa.cicsts.ICeci; import dev.galasa.cicsts.ICeda; import dev.galasa.cicsts.ICemt; +import dev.galasa.cicsts.ITsqFactory; import dev.galasa.cicsts.MasType; import dev.galasa.cicsts.cicsresource.CicsJvmserverResourceException; import dev.galasa.cicsts.cicsresource.ICicsResource; @@ -29,6 +30,7 @@ public abstract class BaseCicsImpl implements ICicsRegionProvisioned { private ICeci ceci; private ICeda ceda; private ICemt cemt; + private ITsqFactory tsq; private ICicsResource cicsResource; private IZosUNIXFile runTemporaryUNIXPath; @@ -93,6 +95,14 @@ public ICeda ceda() throws CicstsManagerException { return this.ceda; } + @Override + public ITsqFactory getTsqFactory() throws CicstsManagerException { + if (this.tsq == null) { + this.tsq = this.cicstsManager.getTsqProvider().getTsqFactory(this, this.cicstsManager); + } + return this.tsq; + } + @Override public ICemt cemt() throws CicstsManagerException { if (this.cemt == null) { diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/spi/ICicstsManagerSpi.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/spi/ICicstsManagerSpi.java index 3b6c79737..e2882d905 100644 --- a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/spi/ICicstsManagerSpi.java +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/spi/ICicstsManagerSpi.java @@ -1,8 +1,8 @@ -/* - * Copyright contributors to the Galasa project - * - * SPDX-License-Identifier: EPL-2.0 - */ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ package dev.galasa.cicsts.spi; import java.util.List; @@ -44,6 +44,13 @@ public interface ICicstsManagerSpi { * @param cedaProvider - the new provider */ void registerCedaProvider(@NotNull ICedaProvider cedaProvider); + + /** + * Register the a ITsq instance provider with the CICS TS Manager + * + * @param tsqProvider - the new provider + */ + void registerTsqProvider(@NotNull ITsqProvider tsqProvider); /** * Register the a ICicsResource instance provider with the CICS TS Manager @@ -73,6 +80,13 @@ public interface ICicstsManagerSpi { @NotNull public ICedaProvider getCedaProvider() throws CicstsManagerException; + /** + * @return The registered TSQ provider + * @throws CicstsManagerException + */ + @NotNull + public ITsqProvider getTsqProvider() throws CicstsManagerException; + /** * @return The registered CICS Resource provider * @throws CicstsManagerException diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/spi/ITsqProvider.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/spi/ITsqProvider.java new file mode 100644 index 000000000..c8a533a14 --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.manager/src/main/java/dev/galasa/cicsts/spi/ITsqProvider.java @@ -0,0 +1,31 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package dev.galasa.cicsts.spi; + +import javax.validation.constraints.NotNull; + +import dev.galasa.cicsts.ITsqFactory; +import dev.galasa.cicsts.TsqManagerException; +import dev.galasa.cicsts.ICicsRegion; + +/** + * Provides CICS Region related TSQ objects + * + */ +public interface ITsqProvider { + + /** + * Returns a unique instance of the ITsqFactory per CICS region + * + * @param cicsRegion + * @param cicstsManager + * @return ITsqFactory object for this CICS region, will have a different instance for different regions + * @throws TsqManagerException if getTsqFactory() fails + */ + @NotNull + ITsqFactory getTsqFactory(ICicsRegion cicsRegion, ICicstsManagerSpi cicstsManager) throws TsqManagerException; + +} \ No newline at end of file diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager.ivt/bnd.bnd b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager.ivt/bnd.bnd new file mode 100644 index 000000000..d418344c5 --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager.ivt/bnd.bnd @@ -0,0 +1,5 @@ +-snapshot: ${tstamp} +Bundle-Name: Galasa TSQ Manager IVTs +Export-Package: dev.galasa.cicsts.tsq.manager.ivt +Import-Package: !javax.validation.constraints, \ + * diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager.ivt/build.gradle b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager.ivt/build.gradle new file mode 100644 index 000000000..8e9453055 --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager.ivt/build.gradle @@ -0,0 +1,27 @@ +plugins { + id 'galasa.manager.ivt' +} + +description = 'Galasa TSQ Manager IVTs' + +version = '0.1.0' + +dependencies { + implementation project (':galasa-managers-core-parent:dev.galasa.core.manager') + implementation project (':galasa-managers-cicsts-parent:dev.galasa.cicsts.tsq.manager') + implementation project (':galasa-managers-zos-parent:dev.galasa.zos3270.manager') +} + + +// Note: These values are consumed by the parent build process +// They indicate which packages of functionality this OSGi bundle should be delivered inside, +// or referenced from. +// The settings here are gathered together by the build process to create a release.yaml file +// which gathers-up all the packaging metadata about all the OSGi bundles in this component. +ext.projectName=project.name +ext.includeInOBR = true +ext.includeInMVP = true +ext.includeInBOM = true +ext.includeInIsolated = true +ext.includeInCodeCoverage = false +ext.includeInJavadoc = false diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager.ivt/settings.gradle b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager.ivt/settings.gradle new file mode 100644 index 000000000..f2ef69561 --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager.ivt/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'dev.galasa.cicsts.tsq.manager.ivt' + diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager.ivt/src/main/java/dev/galasa/cicsts/tsq/manager/ivt/TsqManagerIVT.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager.ivt/src/main/java/dev/galasa/cicsts/tsq/manager/ivt/TsqManagerIVT.java new file mode 100644 index 000000000..5fedaf803 --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager.ivt/src/main/java/dev/galasa/cicsts/tsq/manager/ivt/TsqManagerIVT.java @@ -0,0 +1,235 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package dev.galasa.cicsts.tsq.manager.ivt; + +import dev.galasa.BeforeClass; +import dev.galasa.Test; +import dev.galasa.core.manager.Logger; +import org.apache.commons.logging.Log; + +import dev.galasa.cicsts.CicsRegion; +import dev.galasa.cicsts.CicsTerminal; +import dev.galasa.cicsts.CicstsManagerException; +import dev.galasa.cicsts.ICicsRegion; +import dev.galasa.cicsts.ICicsTerminal; +import dev.galasa.cicsts.ITsq; +import dev.galasa.cicsts.ITsqFactory; + +import dev.galasa.zos3270.FieldNotFoundException; +import dev.galasa.zos3270.KeyboardLockedException; +import dev.galasa.zos3270.TerminalInterruptedException; +import dev.galasa.zos3270.spi.NetworkException; +import dev.galasa.zos3270.TimeoutException; + +import static org.assertj.core.api.Assertions.assertThat; + +@Test +public class TsqManagerIVT { + + @Logger + public Log logger; + + @CicsRegion(cicsTag="A") + public ICicsRegion cicsRegionA; + + @CicsTerminal(cicsTag="A") + public ICicsTerminal cemtTerminalA; + + public ITsqFactory tsqFactoryA; + public ITsq tsqRecoverable; + public ITsq tsqNonRecoverable; + + /** + * Create TSQ Factory instance and ITsq objects + * @throws CicstsManagerException + */ + @BeforeClass + public void createTsqInstance() throws CicstsManagerException { + this.tsqFactoryA = cicsRegionA.getTsqFactory(); + // Create ITsq object for recoverable TSQ + tsqRecoverable = this.tsqFactoryA.createQueue("GALASAR", true); + // Create ITsq object for non-recoverable TSQ + tsqNonRecoverable = this.tsqFactoryA.createQueue("GALASAN", false); + } + + /** + * Check if recoverable TSQ exists + * + * @throws CicstsManagerException + **/ + @Test + public void testRecoverableTsqNotExists() throws CicstsManagerException { + boolean response = tsqRecoverable.exists(); + assertThat(response).as("Recoverable TSQ (GALASAR) is existing.").isEqualTo(false); + } + + /** + * Check if non-recoverable TSQ exists + * + * @throws CicstsManagerException + **/ + @Test + public void testNonRecoverableTsqNotExists() throws CicstsManagerException { + boolean response = tsqNonRecoverable.exists(); + assertThat(response).as("Non Recoverable TSQ (GALASAN) is existing.").isEqualTo(false); + } + + /** + * Tests that the recoverable TSQ is created and data is written + * + * @throws CicstsManagerException + * @throws FieldNotFoundException + * @throws KeyboardLockedException + * @throws NetworkException + * @throws TerminalInterruptedException + * @throws TimeoutException + **/ + @Test + public void testCreateRecoverableTsq() throws CicstsManagerException, FieldNotFoundException, KeyboardLockedException, NetworkException, TerminalInterruptedException, TimeoutException { + String writeMessage = "001 - This message is written from Galasa to the recoverable TSQ named GALASAR."; + // Create and write message to TSQ - GALASAR with recoverable status as true + tsqRecoverable.writeQueue(writeMessage); + + // Check if the CICS TSQUEUE - GALASAR is recoverable + boolean response = tsqRecoverable.isRecoverable(); + assertThat(response).as("TSQ (GALASAR) is not recoverable.").isEqualTo(true); + + // Read message from TSQ and validate + String readMessage = tsqRecoverable.readQueue(1); + assertThat(readMessage).as("TSQ (GALASAR) message read is not equal to the message written.").isEqualTo(writeMessage); + } + + /** + * Tests that the data is written if TSQ is existing and recoverable status is not updated + * + * @throws CicstsManagerException + * @throws FieldNotFoundException + * @throws KeyboardLockedException + * @throws NetworkException + * @throws TerminalInterruptedException + * @throws TimeoutException + **/ + @Test + public void testCreateNonRecoverableTsqForExisting() throws CicstsManagerException, FieldNotFoundException, KeyboardLockedException, NetworkException, TerminalInterruptedException, TimeoutException { + String writeMessage = "002 - This message is written from Galasa to the recoverable TSQ named GALASAR."; + // Create and write message to TSQ - GALASAR with recoverable as false + tsqRecoverable = tsqFactoryA.createQueue("GALASAR", false); + + // Write second message to TSQ - GALASAR + tsqRecoverable.writeQueue(writeMessage); + + // Check if the CICS TSQUEUE - GALASAR is still recoverable + boolean response = tsqRecoverable.isRecoverable(); + assertThat(response).as("TSQ (GALASAR) is not recoverable.").isEqualTo(true); + + + // Read second message from TSQ and validate + String readMessage = tsqRecoverable.readQueue(2); + assertThat(readMessage).as("TSQ (GALASAR) message read is not equal to the message written.").isEqualTo(writeMessage); + } + + /** + * Check if Recoverable TSQ exists + * + * @throws CicstsManagerException + **/ + @Test + public void testRecoverableTsqExists() throws CicstsManagerException { + boolean response = tsqRecoverable.exists(); + assertThat(response).as("Recoverable TSQ (GALASAR) is not existing.").isEqualTo(true); + } + + /** + * Tests that if non recoverable TSQ is created and data is written + * + * @throws CicstsManagerException + * @throws FieldNotFoundException + * @throws KeyboardLockedException + * @throws NetworkException + * @throws TerminalInterruptedException + * @throws TimeoutException + **/ + @Test + public void testCreateNonRecoverableTsq() throws CicstsManagerException, FieldNotFoundException, KeyboardLockedException, NetworkException, TerminalInterruptedException, TimeoutException { + String writeMessage = "001 - This message is written from Galasa to the non-recoverable TSQ named GALASAN."; + + // Create and write message to TSQ - GALASAN + tsqNonRecoverable.writeQueue(writeMessage); + + // Check if the CICS TSQUEUE - GALASAN is non recoverable + boolean response = tsqNonRecoverable.isRecoverable(); + assertThat(response).as("TSQ (GALASAN) is recoverable.").isEqualTo(false); + + // Read message from non-recoverable TSQ and validate + String readMessage = tsqNonRecoverable.readQueue(1); + assertThat(readMessage).as("TSQ (GALASAN) message read is not equal to the message written.").isEqualTo(writeMessage); + } + + /** + * Check if NonRecoverable exists + * + * @throws CicstsManagerException + **/ + @Test + public void testNonRecoverableTsqExists() throws CicstsManagerException { + boolean response = tsqNonRecoverable.exists(); + assertThat(response).as("Non Recoverable TSQ (GALASAN) is not existing.").isEqualTo(true); + } + /** + * Tests that the non recoverable TSQ is deleted + * + * @throws CicstsManagerException + * @throws FieldNotFoundException + * @throws KeyboardLockedException + * @throws NetworkException + * @throws TerminalInterruptedException + * @throws TimeoutException + **/ + @Test + public void testTsqDelete() throws CicstsManagerException, FieldNotFoundException, KeyboardLockedException, NetworkException, TerminalInterruptedException, TimeoutException { + + // Delete TSQ + tsqNonRecoverable.deleteQueue(); + + // Check if the TSQ - GALASAN is not existing after deleteQueue + boolean response = tsqNonRecoverable.exists(); + assertThat(response).as("Non Recoverable TSQ (GALASAN) is existing.").isEqualTo(false); + } + + /** + * Tests that the non-recoverable TSQ is created and data is written. + * Validate if the readQueueNext() works as expected. + * + * @throws CicstsManagerException + */ + @Test + public void testTsqReadNext() throws CicstsManagerException { + + // Write 4 messages to TSQ - GALASAN + String writeMessage1 = "01) This message is written from Galasa to the TSQ named GALASAN."; + tsqNonRecoverable.writeQueue(writeMessage1); + String writeMessage2 = "02) This message is written from Galasa to the TSQ named GALASAN."; + tsqNonRecoverable.writeQueue(writeMessage2); + String writeMessage3 = "03) This message is written from Galasa to the TSQ named GALASAN."; + tsqNonRecoverable.writeQueue(writeMessage3); + String writeMessage4 = "04) This message is written from Galasa to the TSQ named GALASAN."; + tsqNonRecoverable.writeQueue(writeMessage4); + + // Read next and validate the messages starting from item 1 + String readMessage = tsqNonRecoverable.readQueue(1); + assertThat(readMessage).as("Error in reading the first data.").isEqualTo(writeMessage1); + readMessage = tsqNonRecoverable.readQueueNext(); + assertThat(readMessage).as("Error in reading the second data.").isEqualTo(writeMessage2); + readMessage = tsqNonRecoverable.readQueueNext(); + assertThat(readMessage).as("Error in reading the third data.").isEqualTo(writeMessage3); + readMessage = tsqNonRecoverable.readQueueNext(); + assertThat(readMessage).as("Error in reading the fourth data.").isEqualTo(writeMessage4); + + // READ_ERROR when no more items to read. + readMessage = tsqNonRecoverable.readQueueNext(); + assertThat(readMessage).as("Non Recoverable TSQ (GALASAN) contains more data.").isEqualTo("READ_ERROR"); + } +} \ No newline at end of file diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/bnd.bnd b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/bnd.bnd new file mode 100644 index 000000000..001335e5a --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/bnd.bnd @@ -0,0 +1,5 @@ +-snapshot: ${tstamp} +Bundle-Name: Galasa CICS/TS TSQ Manager +Export-Package: dev.galasa.cicsts.tsq.spi +Import-Package: !javax.validation.constraints, \ + * diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/build.gradle b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/build.gradle new file mode 100644 index 000000000..76c669010 --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/build.gradle @@ -0,0 +1,28 @@ +plugins { + id 'galasa.manager' +} + +description = 'Galasa CICS/TS TSQ Manager' + +version = '0.1.0' + +dependencies { + api project (':galasa-managers-cicsts-parent:dev.galasa.cicsts.manager') + implementation project (':galasa-managers-zos-parent:dev.galasa.zos3270.manager') +} + + +// Note: These values are consumed by the parent build process +// They indicate which packages of functionality this OSGi bundle should be delivered inside, +// or referenced from. +// The settings here are gathered together by the build process to create a release.yaml file +// which gathers-up all the packaging metadata about all the OSGi bundles in this component. +ext.projectName=project.name +ext.includeInOBR = true +ext.includeInMVP = true +ext.includeInBOM = true +ext.includeInIsolated = true +ext.includeInCodeCoverage = true +ext.includeInJavadoc = true + + diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/settings.gradle b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/settings.gradle new file mode 100644 index 000000000..ae20d3c38 --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'dev.galasa.cicsts.tsq.manager' + diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/TsqFactoryImpl.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/TsqFactoryImpl.java new file mode 100644 index 000000000..8e2ae859d --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/TsqFactoryImpl.java @@ -0,0 +1,192 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package dev.galasa.cicsts.tsq.internal; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + +import javax.validation.constraints.NotNull; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import dev.galasa.cicsts.TsqException; +import dev.galasa.cicsts.TsqManagerException; +import dev.galasa.cicsts.CicstsManagerException; +import dev.galasa.cicsts.ITsqFactory; +import dev.galasa.cicsts.ITsq; +import dev.galasa.cicsts.ICicsRegion; +import dev.galasa.cicsts.ICicsTerminal; +import dev.galasa.cicsts.IExecInterfaceBlock; +import dev.galasa.cicsts.ICeci; +import dev.galasa.cicsts.ICeda; +import dev.galasa.cicsts.ICemt; +import dev.galasa.cicsts.ICeciResponse; +import dev.galasa.cicsts.CeciException; +import dev.galasa.cicsts.CedaException; +import dev.galasa.cicsts.CemtException; +import dev.galasa.cicsts.spi.ICicstsManagerSpi; +import dev.galasa.zos3270.FieldNotFoundException; +import dev.galasa.zos3270.KeyboardLockedException; +import dev.galasa.zos3270.TerminalInterruptedException; +import dev.galasa.zos3270.TimeoutException; +import dev.galasa.zos3270.spi.NetworkException; +import dev.galasa.cicsts.CicstsHashMap; + +/** + * Implementation of {@link ITsq} + */ +public class TsqFactoryImpl implements ITsqFactory { + + private static final Log logger = LogFactory.getLog(TsqFactoryImpl.class); + + private final ICicsRegion cicsRegion; + private final ICicsTerminal cedaTerminal; + private final ICicsTerminal cemtTerminal; + private final ICicstsManagerSpi cicstsManager; + private final TsqManagerImpl tsqManager; + private final ICeda ceda; + private final ICemt cemt; + private String queueName; + + public TsqFactoryImpl(TsqManagerImpl manager, ICicsRegion cicsRegion, ICicstsManagerSpi cicstsManager) throws TsqException { + this.cicsRegion = cicsRegion; + this.cicstsManager = cicstsManager; + this.tsqManager = manager; + try { + this.ceda = cicsRegion.ceda(); + } catch (CicstsManagerException e) { + throw new TsqException("Unable to get CEDA instance for CICS region", e); + } + try { + this.cemt = cicsRegion.cemt(); + } catch (CicstsManagerException e) { + throw new TsqException("Unable to get CEMT instance for CICS region", e); + } + try { + this.cedaTerminal = cicstsManager.generateCicsTerminal(cicsRegion.getTag()); + this.cedaTerminal.connectToCicsRegion(); + this.cedaTerminal.clear(); + } catch (CicstsManagerException | KeyboardLockedException | NetworkException | TerminalInterruptedException e) { + throw new TsqException("Unable to get CEDA terminal for CICS region", e); + } + try { + this.cemtTerminal = cicstsManager.generateCicsTerminal(cicsRegion.getTag()); + this.cemtTerminal.connectToCicsRegion(); + this.cemtTerminal.resetAndClear(); + } catch (CicstsManagerException e) { + throw new TsqException("Unable to get CEMT terminal for CICS region", e); + } + } + + /* + * Create the CICS resource TSMODEL if TSQ is recoverable. + * Create and return the ITsq object for the queueName provided. + */ + @Override + public ITsq createQueue(String queueName, boolean isRecoverable) throws TsqException { + this.queueName = queueName; + checkQueueName(); + + // If recoverable is true create a TSMODEL to make the TSQ as recoverable + if (isRecoverable) { + this.setRecoverable(queueName); + } + + // Create new ITsq object for the queueName + try { + ITsq response = this.createQueue(queueName); + return response; + } catch (TsqException e) { + throw new TsqException(String.format("Failed to create TSQ : (%s)", queueName), e); + } + } + + /* + * Create and return the ITsq object for the queueName provided. + */ + @Override + public ITsq createQueue(String queueName) throws TsqException { + this.queueName = queueName; + checkQueueName(); + + // Check if TSQ is already exiting. + try { + CicstsHashMap cemtInquireTSQ = this.cemt.inquireResource(this.cemtTerminal, "TSQUEUE", queueName); + // Issue WARNING if TSQ is already existing + if( cemtInquireTSQ != null ) { + logger.warn(String.format("TSQ is already existing. Recoverable status will be based on existing TSQ : (%s).", queueName)); + } + } catch ( CemtException e ) { + throw new TsqException("Failed to inquire the existence of TSQ : " + queueName, e); + } + + // Create new ITsq object for the queueName + try { + ITsq response = new TsqImpl(tsqManager, cicsRegion, cicstsManager, queueName); + return response; + } catch (TsqException e) { + throw new TsqException("Failed to write to TSQ : " + queueName, e); + } + } + + /* + * Create TSMODEL to make TSQ recoverable + */ + private void setRecoverable(String queueName) throws TsqException { + // Generate model name + String modelName = resolveModelName(); + + // Check if TSMODEL is already exiting. + try { + CicstsHashMap cemtInquireTSModel = this.cemt.inquireResource(this.cemtTerminal, "TSMODEL", modelName); + // Issue a warning if TSMODEL is already existing + if( cemtInquireTSModel != null ) { + logger.warn(String.format("TSQMODEL (%s) is already existing for TSQ (%s). Recoverable status will be based on existing TSMODEL.", modelName, queueName)); + } else { + try { + // Create TSMODEL using CEDA command to make TSQ recoverable + this.ceda.createResource(this.cedaTerminal, "TSMODEL", modelName, modelName, String.format("PREFIX(%s) RECOVERY(YES)", queueName)); + // Install TSMODEL using CEDA command to make TSQ recoverable + this.ceda.installResource(this.cedaTerminal, "TSMODEL", modelName, modelName); + } catch(CedaException e) { + throw new TsqException(String.format("Failed to make TSQ : (%s) recoverable.", queueName), e); + } + } + } catch ( CemtException e ) { + throw new TsqException("Failed to inquire the existence of TSMODEL : " + modelName, e); + } + return; + } + + /** + * Generates a TS model name based on the TSQ name. + * If the TSQ name is less than 8 characters long, it is appened with 'M'. Otherwise the 8th character is changed to be an 'M'. + * + * If the TSQ name is: 'QUEUE ', then the model name is: 'QUEUEM '. + * If the TSQ name is: 'FEATUREQ', then the model name is: 'FEATUREM'. + */ + private String resolveModelName() { + if(this.queueName.length() < 8) { + return this.queueName + "M"; + } else { + return this.queueName.substring(0,7) + "M"; + } + } + + /** + * Check if the queue name is empty and throw error if empty. + */ + public void checkQueueName() throws TsqException { + if (this.queueName.trim().length() == 0){ + throw new TsqException("TSQ queue name cannot be blank."); + } + return; + } + +} diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/TsqImpl.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/TsqImpl.java new file mode 100644 index 000000000..32a31db1d --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/TsqImpl.java @@ -0,0 +1,305 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package dev.galasa.cicsts.tsq.internal; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + +import javax.validation.constraints.NotNull; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import dev.galasa.cicsts.TsqException; +import dev.galasa.cicsts.TsqManagerException; +import dev.galasa.cicsts.CicstsManagerException; +import dev.galasa.cicsts.ITsq; +import dev.galasa.cicsts.ICicsRegion; +import dev.galasa.cicsts.ICicsTerminal; +import dev.galasa.cicsts.IExecInterfaceBlock; +import dev.galasa.cicsts.ICeci; +import dev.galasa.cicsts.ICeda; +import dev.galasa.cicsts.ICemt; +import dev.galasa.cicsts.ICeciResponse; +import dev.galasa.cicsts.CeciException; +import dev.galasa.cicsts.CedaException; +import dev.galasa.cicsts.CemtException; +import dev.galasa.cicsts.spi.ICicstsManagerSpi; +import dev.galasa.zos3270.FieldNotFoundException; +import dev.galasa.zos3270.KeyboardLockedException; +import dev.galasa.zos3270.TerminalInterruptedException; +import dev.galasa.zos3270.TimeoutException; +import dev.galasa.zos3270.spi.NetworkException; +import dev.galasa.cicsts.CicstsHashMap; + +/** + * Implementation of {@link ITsq} + */ +public class TsqImpl implements ITsq { + + private static final Log logger = LogFactory.getLog(TsqImpl.class); + + private final ICicsRegion cicsRegion; + private final ICicsTerminal ceciTerminal; + private final ICicsTerminal cemtTerminal; + private final ICicstsManagerSpi cicstsManager; + private final ICeci ceci; + private final ICemt cemt; + private String queueName; + + public TsqImpl(TsqManagerImpl manager, ICicsRegion cicsRegion, ICicstsManagerSpi cicstsManager, String queueName) throws TsqException { + this.cicsRegion = cicsRegion; + this.cicstsManager = cicstsManager; + this.queueName = queueName; + try { + this.ceci = cicsRegion.ceci(); + } catch (CicstsManagerException e) { + throw new TsqException("Unable to get CECI instance for CICS region", e); + } + try { + this.cemt = cicsRegion.cemt(); + } catch (CicstsManagerException e) { + throw new TsqException("Unable to get CEMT instance for CICS region", e); + } + try { + this.ceciTerminal = cicstsManager.generateCicsTerminal(cicsRegion.getTag()); + this.ceciTerminal.connectToCicsRegion(); + this.ceciTerminal.clear(); + } catch (CicstsManagerException | KeyboardLockedException | NetworkException | TerminalInterruptedException e) { + throw new TsqException("Unable to get CECI terminal for CICS region", e); + } + try { + this.cemtTerminal = cicstsManager.generateCicsTerminal(cicsRegion.getTag()); + this.cemtTerminal.connectToCicsRegion(); + this.cemtTerminal.resetAndClear(); + } catch (CicstsManagerException e) { + throw new TsqException("Unable to get CEMT terminal for CICS region", e); + } + } + + /* + * Check the exitence of TSQ + */ + @Override + public boolean exists() throws TsqException { + boolean response = true; + try { + // Check if TSQ is already exiting. + CicstsHashMap cemtInquireTSQ = this.cemt.inquireResource(this.cemtTerminal, "TSQUEUE", this.queueName); + if( cemtInquireTSQ == null ) { + response = false; + } + } catch ( CemtException e ) { + throw new TsqException("Failed to inquire the existence of TSQ : " + queueName, e); + } + return response; + } + + /* + * Check if the TSQ is recoverable + */ + @Override + public boolean isRecoverable() throws TsqException { + boolean response = false; + try { + CicstsHashMap cemtInquireTSQ = this.cemt.inquireResource(this.cemtTerminal, "TSQUEUE", this.queueName); + if( cemtInquireTSQ != null ) { + // Check if TSQ is recoverable + if (cemtInquireTSQ.get("recovstatus").equals("Recoverable")) { + response = true; + } + } else { + throw new TsqException(String.format("The TSQ (%s) does not exist, so cannot check if it is recoverable.", queueName)); + } + } catch ( CemtException e ) { + throw new TsqException("Failed to inquire the existence of TSQ : " + queueName, e); + } + return response; + } + + /* + * Write to the TSQ + */ + @Override + public void writeQueue(String data) throws TsqException { + // Check if queueName is not empty + this.checkQueueName(); + // Check if data to write to TSQ is not blank + this.checkData(data); + + // Create WRITEQ command to execute using CECI + String command = String.format("WRITEQ TS FROM(&INPUTDATA) %s", this.setQueueNameforCECI()); + + try { + // Start CECI session in the terminal + this.ceci.startCECISession(this.ceciTerminal); + + // Create variable to write data to TSQ + int varLength = this.ceci.defineVariableText(this.ceciTerminal, "&INPUTDATA", data); + logger.info(String.format("Message length written to variable is : %s", varLength)); + logger.info(String.format("Message written is : %s", data)); + + } catch (CeciException e) { + throw new TsqException(String.format("Failed to create variable for input data to write to TSQ : (%s).", this.queueName), e); + } + + try { + // Write to TSQ using using CECI command + ICeciResponse resp = this.ceci.issueCommand(this.ceciTerminal, command); + if (!resp.isNormal()) { + throw new TsqException(String.format("Write failed for TSQ : (%s). CICS response: %s", this.queueName, resp.getResponse())); + } else { + logger.info(String.format("Written '%s' to TSQ - %s successful.",data , this.queueName )); + } + } catch (CeciException e) { + throw new TsqException(String.format("Failed to write to TSQ : (%s).", this.queueName) , e); + } + + // Delete the &INPUTDATA variable after writing to TSQ for next WRITEQ command + try{ + this.ceci.deleteVariable(this.ceciTerminal, "&INPUTDATA"); + } catch (CeciException e) { + throw new TsqException(String.format("Failed to delete variable used to write to TSQ : (%s).", this.queueName), e); + } + return; + } + + /* + * Read the TSQ based on the item number + */ + @Override + public String readQueue(int item) throws TsqException{ + // Check if queueName is not empty + this.checkQueueName(); + String data = ""; + + // Create READQ command to execute using CECI + String command = String.format("READQ TS INTO(&OUTDATA) %s ITEM(%s)", this.setQueueNameforCECI(), item); + + try { + //Start CECI session in the terminal + this.ceci.startCECISession(this.ceciTerminal); + // Read TSQ using CECI command + ICeciResponse resp = this.ceci.issueCommand(this.ceciTerminal, command); + if (resp.isNormal()) { + try { + // Retrieve the text read from TSQ + data = this.ceci.retrieveVariableText(this.ceciTerminal, "&OUTDATA"); + } catch (CeciException e) { + throw new TsqException("Read TSQ failed while trying to retrieve the data. ", e); + } + } else if (resp.getResponse().equals("ITEMERR")) { + // If invalid ITEM number in READQ command + data = "READ_ERROR"; + logger.error(String.format("There is no item (%s) to read from TSQ : (%s). CICS response : %s ", item, this.queueName, resp.getResponse())); + } else { + throw new TsqException(String.format("TSQ read failed for queue : (%s). CICS response : %s.", this.queueName, resp.getResponse())); + } + } catch (CeciException e) { + throw new TsqException(String.format("Failed to read TSQ : (%s).", this.queueName), e); + } + return data; + } + + /* + * Read next entry in TSQ + */ + @Override + public String readQueueNext() throws TsqException{ + // Check if queueName is not empty + this.checkQueueName(); + String data = ""; + + // Create READQ command to execute using CECI + String command = String.format("READQ TS INTO(&OUTDATA) %s NEXT", this.setQueueNameforCECI()); + + try { + //Start CECI session in the terminal + this.ceci.startCECISession(this.ceciTerminal); + // Read TSQ using CECI command + ICeciResponse resp = this.ceci.issueCommand(this.ceciTerminal, command); + if (resp.isNormal()) { + try { + // Retrieve the text read from TSQ + data = this.ceci.retrieveVariableText(this.ceciTerminal, "&OUTDATA"); + } catch (CeciException e) { + throw new TsqException("Read TSQ failed while trying to retrieve the data. ", e); + } + } else if (resp.getResponse().equals("ITEMERR")) { + // If no more data in TSQ + data = "READ_ERROR"; + logger.error(String.format("There is no item to read from TSQ : (%s). CICS response : %s ", this.queueName, resp.getResponse())); + } + else { + throw new TsqException(String.format("TSQ read failed for queue : (%s). CICS response : %s.", this.queueName, resp.getResponse())); + } + } catch (CeciException e) { + throw new TsqException(String.format("Failed to read TSQ : (%s).", this.queueName), e); + } + return data; + } + + /* + * To delete TSQ + */ + @Override + public void deleteQueue() throws TsqException { + // Check if queueName is not empty + this.checkQueueName(); + + // Create DELETEQ command to execute using CECI + String command = String.format("DELETEQ TS %s", this.setQueueNameforCECI()); + + try { + // Start CECI session in the terminal + this.ceci.startCECISession(this.ceciTerminal); + + // Delete TSQ using using CECI command + ICeciResponse resp = this.ceci.issueCommand(this.ceciTerminal, command); + if (!resp.isNormal()) { + throw new TsqException(String.format("Delete failed for TSQ : (%s). CICS response: %s", this.queueName, resp.getResponse())); + } + } catch(CeciException e) { + throw new TsqException(String.format("Failed to delete TSQ : (%s).", this.queueName), e); + } + return; + } + + // Set Queue name for CECI commands + private String setQueueNameforCECI() { + StringBuilder command = new StringBuilder(); + if(this.queueName.length() > 8) { + // Use QNAME where the TSQ name is greater than 8 characters. + command.append(String.format("QNAME(%s)", this.queueName)); + } else { + // Use QUEUE where the TSQ name is less than or equal to 8 characters. + command.append(String.format("QUEUE(%s)", this.queueName)); + } + return command.toString(); + } + + /** + * Check if the queue name is empty and throw error if empty. + */ + public void checkQueueName() throws TsqException { + if (this.queueName.trim().length() == 0){ + throw new TsqException("TSQ queue name cannot be blank."); + } + return; + } + + /** + * Check if the data is empty and throw error if empty. + */ + public void checkData(String data) throws TsqException { + if (data.trim().length() == 0){ + throw new TsqException(String.format("Data cannot be blank to write to TSQ : (%s)", this.queueName)); + } + return; + } +} diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/TsqManagerImpl.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/TsqManagerImpl.java new file mode 100644 index 000000000..8a85ae7e8 --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/TsqManagerImpl.java @@ -0,0 +1,99 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package dev.galasa.cicsts.tsq.internal; + +import java.util.HashMap; +import java.util.List; + +import javax.validation.constraints.NotNull; + +import org.osgi.service.component.annotations.Component; + +import dev.galasa.ManagerException; +import dev.galasa.cicsts.TsqException; +import dev.galasa.cicsts.TsqManagerException; +import dev.galasa.cicsts.CicstsManagerException; +import dev.galasa.cicsts.ITsqFactory; +import dev.galasa.cicsts.ICicsRegion; +import dev.galasa.cicsts.tsq.internal.properties.TsqPropertiesSingleton; +import dev.galasa.cicsts.tsq.spi.ITsqManagerSpi; +import dev.galasa.cicsts.spi.ITsqProvider; +import dev.galasa.cicsts.spi.ICicstsManagerSpi; +import dev.galasa.framework.spi.AbstractManager; +import dev.galasa.framework.spi.ConfigurationPropertyStoreException; +import dev.galasa.framework.spi.IFramework; +import dev.galasa.framework.spi.IManager; +import dev.galasa.framework.spi.ResourceUnavailableException; +import dev.galasa.framework.spi.language.GalasaTest; + +@Component(service = { IManager.class }) +public class TsqManagerImpl extends AbstractManager implements ITsqManagerSpi, ITsqProvider { + + protected static final String NAMESPACE = "tsq"; + private ICicstsManagerSpi cicstsManager; + + protected HashMap regionTsqs = new HashMap<>(); + + /* (non-Javadoc) + * @see dev.galasa.framework.spi.AbstractManager#initialise(dev.galasa.framework.spi.IFramework, java.util.List, java.util.List, java.lang.Class) + */ + @Override + public void initialise(@NotNull IFramework framework, @NotNull List allManagers, @NotNull List activeManagers, @NotNull GalasaTest galasaTest) throws ManagerException { + super.initialise(framework, allManagers, activeManagers, galasaTest); + try { + TsqPropertiesSingleton.setCps(framework.getConfigurationPropertyService(NAMESPACE)); + } catch (ConfigurationPropertyStoreException e) { + throw new TsqManagerException("Unable to request framework services", e); + } + + if(galasaTest.isJava()) { + youAreRequired(allManagers, activeManagers, galasaTest); + } + } + + /* (non-Javadoc) + * @see dev.galasa.framework.spi.AbstractManager#provisionGenerate() + */ + @Override + public void provisionGenerate() throws ManagerException, ResourceUnavailableException { + } + + + /* (non-Javadoc) + * @see dev.galasa.framework.spi.AbstractManager#youAreRequired() + */ + @Override + public void youAreRequired(@NotNull List allManagers, @NotNull List activeManagers, @NotNull GalasaTest galasaTest) throws ManagerException { + if (activeManagers.contains(this)) { + return; + } + + activeManagers.add(this); + + cicstsManager = addDependentManager(allManagers, activeManagers, galasaTest, ICicstsManagerSpi.class); + if(cicstsManager == null) { + throw new CicstsManagerException("CICS Manager is not available"); + } + + cicstsManager.registerTsqProvider(this); + + } + + // Get ITsqFactory instance for the CICS Region + @Override + public @NotNull ITsqFactory getTsqFactory(ICicsRegion cicsRegion, ICicstsManagerSpi cicstsManager) throws TsqManagerException{ + ITsqFactory tsq = this.regionTsqs.get(cicsRegion); + if (tsq == null) { + try{ + tsq = new TsqFactoryImpl(this, cicsRegion, cicstsManager); + this.regionTsqs.put(cicsRegion, tsq); + } catch (TsqException e) { + throw new TsqManagerException("TSQ instance implemenation failed. ", e); + } + } + return tsq; + } +} diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/package-info.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/package-info.java new file mode 100644 index 000000000..14c82443f --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/package-info.java @@ -0,0 +1,9 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +/** + * CICS/TS TSQ Manager - Internal Implementation + */ +package dev.galasa.cicsts.tsq.internal; \ No newline at end of file diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/properties/TsqPropertiesSingleton.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/properties/TsqPropertiesSingleton.java new file mode 100644 index 000000000..18f93e090 --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/properties/TsqPropertiesSingleton.java @@ -0,0 +1,51 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package dev.galasa.cicsts.tsq.internal.properties; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; + +import dev.galasa.cicsts.TsqManagerException; +import dev.galasa.framework.spi.IConfigurationPropertyStoreService; + +@Component(service=TsqPropertiesSingleton.class, immediate=true) +public class TsqPropertiesSingleton { + + private static TsqPropertiesSingleton singletonInstance; + private static void setInstance(TsqPropertiesSingleton instance) { + singletonInstance = instance; + } + + private IConfigurationPropertyStoreService cps; + + @Activate + public void activate() { + setInstance(this); + } + + @Deactivate + public void deacivate() { + setInstance(null); + } + + public static IConfigurationPropertyStoreService cps() throws TsqManagerException { + if (singletonInstance != null) { + return singletonInstance.cps; + } + + throw new TsqManagerException("Attempt to access manager CPS before it has been initialised"); + } + + public static void setCps(IConfigurationPropertyStoreService cps) throws TsqManagerException { + if (singletonInstance != null) { + singletonInstance.cps = cps; + return; + } + + throw new TsqManagerException("Attempt to set manager CPS before instance created"); + } +} diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/properties/package-info.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/properties/package-info.java new file mode 100644 index 000000000..9da2a516b --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/internal/properties/package-info.java @@ -0,0 +1,13 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +/** + * CICS/TS TSQ Manager - CPS Properties + * + *

+ * The following properties are used by the CICS/TS TSQ Manager:-
+ *

+ */ +package dev.galasa.cicsts.tsq.internal.properties; \ No newline at end of file diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/spi/ITsqManagerSpi.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/spi/ITsqManagerSpi.java new file mode 100644 index 000000000..d5ce45c8e --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/spi/ITsqManagerSpi.java @@ -0,0 +1,13 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package dev.galasa.cicsts.tsq.spi; + +/** + * Provides the SPI access to the CICS/TS TSQ Manager + */ +public interface ITsqManagerSpi { + +} diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/spi/package-info.java b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/spi/package-info.java new file mode 100644 index 000000000..c6a54ade6 --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/src/main/java/dev/galasa/cicsts/tsq/spi/package-info.java @@ -0,0 +1,9 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +/** + * CICS/TS TSQ Manager - Internal SPI + */ +package dev.galasa.cicsts.tsq.spi; \ No newline at end of file diff --git a/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/tsq_manager_codesnippet.md b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/tsq_manager_codesnippet.md new file mode 100644 index 000000000..18853e953 --- /dev/null +++ b/galasa-managers-parent/galasa-managers-cicsts-parent/dev.galasa.cicsts.tsq.manager/tsq_manager_codesnippet.md @@ -0,0 +1,129 @@ +
Request a TSQ Factory instance + +The following snippet shows the code that is required to request a TSQ Factory instance in a Galasa test: + +``` +@CicsRegion() +public ICicsRegion cicsRegion; +public ITsqFactory tsqFactory; + +... + +this.tsqFactory = cicsRegion.getTsqFactory(); + +``` + +
+ +
Create a new ITsq object with a queue name + +The following snippets show the code required to create a new ITsq object. + +In this case, the test will create an ITsq object with queue named GALASAR. The TSQ created using this object will be a recoverable queue. + +``` +public ITsq tsqRecoverable; + +... + +// Create ITsq object for recoverable TSQ +String queueName = "GALASAR"; +boolean isRecoverable = true; +tsqRecoverable = this.tsqFactoryA.createQueue(queueName, isRecoverable); + +``` + +In this case, the test will create an ITsq object with queue named GALASAN. The TSQ created using this object will be a non-recoverable queue. + +``` +public ITsq tsqNonRecoverable; + +... + +// Create ITsq object for non-recoverable TSQ +String queueName = "GALASAN"; +boolean isRecoverable = false; +tsqNonRecoverable = this.tsqFactoryA.createQueue(queueName, isRecoverable); + +``` +Note: If TSQ is already existing then the recoverable status will not change. + +
+ +
Write to TSQ + +The following snippet shows the code required to write data to a TSQ. + +In this case, the test will write the data contained in the variable named writeMessage to the TSQ named GALASAN: + +``` +// Note: Here ITsq object - tsqNonRecoverable is created with queueName = "GALASAN" + +String writeMessage = "Write this message to TSQ named GALASAN."; +tsqNonRecoverable.writeQueue(writeMessage); + +``` + +
+ +
Read from TSQ + +The following snippet shows the code required to read data from a TSQ. + +In this case, the test will read a message into the variable named readMessage, from the TSQ named GALASAN based on the item number passed : + +``` +// Note: Here ITsq object - tsqNonRecoverable is created with queueName = "GALASAN" +int itemNumber = 1; +String readMessage =tsqNonRecoverable.readQueue(itemNumber); + +``` + +In this case, the test will read the next message from the TSQ named GALASAN. Here the variable - readMessage2 will have item number 2 and variable - readMessage3 will have item number 3 : + +``` +String readMessage2 = tsqNonRecoverable.readQueueNext(); +String readMessage3 = tsqNonRecoverable.readQueueNext(); + +``` +
+ +
Delete a TSQ + +The following snippet shows the code required to delete a non-recoverable TSQ. + +In this case, the test will delete the TSQ named GALASAN: + +``` +// Note: Here ITsq object - tsqNonRecoverable is created with queueName = "GALASAN" +tsqNonRecoverable.deleteQueue(); + +``` +
+ +
Check if a TSQ is existing + +The following snippet shows the code required to check the existence of a TSQ. + +In this case, the test will check the existence of the TSQ named GALASAN. The variable - response will be true if the TSQ is existing else it will be false: + +``` +// Note: Here ITsq object - tsqNonRecoverable is created with queueName = "GALASAN" +boolean response = tsqNonRecoverable.exists(); + +``` +
+ + +
Check if a TSQ is recoverable + +The following snippet shows the code required to check if a TSQ is recoverable. + +In this case, the test will check the TSQ named GALASAN if it is recoverable or not. The variable - response will be true if the TSQ is recoverable else it will be false: + +``` +// Note: Here ITsq object - tsqNonRecoverable is created with queueName = "GALASAN" +boolean response = tsqNonRecoverable.isRecoverable(); + +``` +
\ No newline at end of file diff --git a/galasa-managers-parent/settings.gradle b/galasa-managers-parent/settings.gradle index 767ec2472..59374a9fa 100644 --- a/galasa-managers-parent/settings.gradle +++ b/galasa-managers-parent/settings.gradle @@ -60,10 +60,12 @@ include 'galasa-managers-cicsts-parent:dev.galasa.cicsts.manager.ivt' include 'galasa-managers-cicsts-parent:dev.galasa.cicsts.ceci.manager' include 'galasa-managers-cicsts-parent:dev.galasa.cicsts.cemt.manager' include 'galasa-managers-cicsts-parent:dev.galasa.cicsts.ceda.manager' +include 'galasa-managers-cicsts-parent:dev.galasa.cicsts.tsq.manager' include 'galasa-managers-cicsts-parent:dev.galasa.cicsts.resource.manager' include 'galasa-managers-cicsts-parent:dev.galasa.cicsts.ceda.manager.ivt' include 'galasa-managers-cicsts-parent:dev.galasa.cicsts.cemt.manager.ivt' include 'galasa-managers-cicsts-parent:dev.galasa.cicsts.ceci.manager.ivt' +include 'galasa-managers-cicsts-parent:dev.galasa.cicsts.tsq.manager.ivt' // galasa-managers-unix-parent include 'galasa-managers-unix-parent:dev.galasa.linux.manager' include 'galasa-managers-unix-parent:dev.galasa.linux.manager.ivt'