-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add check to verify VSAM file existence (#973)
* Add check for the vsam filename existence and add unit tests Signed-off-by: at670475 <[email protected]> * Refactoring Signed-off-by: at670475 <[email protected]> * Add test file to versioning and fix regex Signed-off-by: at670475 <[email protected]> Co-authored-by: David Janda <[email protected]>
- Loading branch information
Showing
3 changed files
with
299 additions
and
250 deletions.
There are no files selected for viewing
335 changes: 170 additions & 165 deletions
335
caching-service/src/main/java/org/zowe/apiml/caching/service/vsam/VsamFile.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,165 +1,170 @@ | ||
/* | ||
* This program and the accompanying materials are made available under the terms of the | ||
* Eclipse Public License v2.0 which accompanies this distribution, and is available at | ||
* https://www.eclipse.org/legal/epl-v20.html | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Copyright Contributors to the Zowe Project. | ||
*/ | ||
|
||
package org.zowe.apiml.caching.service.vsam; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
import org.zowe.apiml.caching.config.VsamConfig; | ||
import org.zowe.apiml.caching.model.KeyValue; | ||
import org.zowe.apiml.util.ClassOrDefaultProxyUtils; | ||
import org.zowe.apiml.zfile.*; | ||
|
||
import java.io.Closeable; | ||
|
||
/** | ||
* ZFile wrapper providing convenience methods and implementing Closeable interface | ||
* | ||
* Creates a proxy of com.ibm.jzos.ZFileException and wraps it's methods | ||
* | ||
*/ | ||
|
||
@Slf4j | ||
public class VsamFile implements Closeable, ZFile { | ||
|
||
private ZFile zfile; | ||
private VsamConfig vsamConfig; | ||
private String options = "ab+,type=record"; | ||
|
||
public VsamFile(VsamConfig config) { | ||
if (config == null) { | ||
throw new IllegalArgumentException("Cannot create VsamFile with null configuration"); | ||
} | ||
this.vsamConfig = config; | ||
try { | ||
this.zfile = openZfile(); | ||
} catch (ZFileException e) { | ||
throw new IllegalStateException("Failed to open VsamFile"); | ||
} | ||
} | ||
|
||
@Override | ||
public void close() { | ||
|
||
if (zfile != null) { | ||
try { | ||
zfile.close(); | ||
} catch (ZFileException e) { | ||
log.error("Closing ZFile failed"); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* This method writes a record to file and deletes it immediately. | ||
* Use this method on freshly created empty VSAM to write the fist record | ||
* and to verify that records can be written. | ||
* | ||
* Exceptions are thrown to give chance to the caller to react. | ||
* | ||
* @throws ZFileException | ||
* @throws VsamRecordException | ||
*/ | ||
public void warmUpVsamFile() throws ZFileException, VsamRecordException { | ||
|
||
log.info("Warming up the vsam file by writing and deleting a record"); | ||
|
||
log.info("VSAM file being used: {}", zfile.getActualFilename()); | ||
|
||
VsamRecord record = new VsamRecord(vsamConfig, "delete", new KeyValue("me", "novalue")); | ||
|
||
log.info("Writing Record: {}", record); | ||
zfile.write(record.getBytes()); | ||
|
||
boolean found = zfile.locate(record.getKeyBytes(), ZFileConstants.LOCATE_KEY_EQ); | ||
|
||
log.info("Test record for deletion found: {}", found); | ||
if (found) { | ||
byte[] recBuf = new byte[vsamConfig.getRecordLength()]; | ||
zfile.read(recBuf); //has to be read before update/delete | ||
zfile.delrec(); | ||
log.info("Test record deleted."); | ||
} | ||
|
||
} | ||
|
||
@SuppressWarnings({"squid:S1130", "squid:S1192"}) | ||
private ZFile openZfile() throws ZFileException { | ||
return ClassOrDefaultProxyUtils.createProxyByConstructor(ZFile.class, "com.ibm.jzos.ZFile", | ||
ZFileDummyImpl::new, | ||
new Class[] {String.class, String.class}, | ||
new Object[] {vsamConfig.getFileName(), options}, | ||
new ClassOrDefaultProxyUtils.ByMethodName<>( | ||
"com.ibm.jzos.ZFileException", ZFileException.class, | ||
"getFileName", "getMessage", "getErrnoMsg", "getErrno", "getErrno2", "getLastOp", "getAmrcBytes", | ||
"getAbendCode", "getAbendRc", "getFeedbackRc", "getFeedbackFtncd", "getFeedbackFdbk"), | ||
new ClassOrDefaultProxyUtils.ByMethodName<>( | ||
"com.ibm.jzos.RcException", RcException.class, | ||
"getMessage", "getRc"), | ||
new ClassOrDefaultProxyUtils.ByMethodName<>( | ||
"com.ibm.jzos.EnqueueException", EnqueueException.class, | ||
"getMessage", "getRc") | ||
); | ||
} | ||
|
||
@Override | ||
public void delrec() throws ZFileException { | ||
zfile.delrec(); | ||
} | ||
|
||
@Override | ||
public boolean locate(byte[] key, int options) throws ZFileException { | ||
return zfile.locate(key, options); | ||
} | ||
|
||
@Override | ||
public boolean locate(byte[] key, int offset, int length, int options) throws ZFileException { | ||
return zfile.locate(key, offset, length, options); | ||
} | ||
|
||
@Override | ||
public boolean locate(long recordNumberOrRBA, int options) throws ZFileException { | ||
return zfile.locate(recordNumberOrRBA, options); | ||
} | ||
|
||
@Override | ||
public int read(byte[] buf) throws ZFileException { | ||
return zfile.read(buf); | ||
} | ||
|
||
@Override | ||
public int read(byte[] buf, int offset, int len) throws ZFileException { | ||
return zfile.read(buf, offset, len); | ||
} | ||
|
||
@Override | ||
public int update(byte[] buf) throws ZFileException { | ||
return zfile.update(buf); | ||
} | ||
|
||
@Override | ||
public int update(byte[] buf, int offset, int length) throws ZFileException { | ||
return zfile.update(buf, offset, length); | ||
} | ||
|
||
@Override | ||
public void write(byte[] buf) throws ZFileException { | ||
zfile.write(buf); | ||
} | ||
|
||
@Override | ||
public void write(byte[] buf, int offset, int len) throws ZFileException { | ||
zfile.write(buf, offset, len); | ||
} | ||
|
||
@Override | ||
public String getActualFilename() { | ||
return zfile.getActualFilename(); | ||
} | ||
} | ||
/* | ||
* This program and the accompanying materials are made available under the terms of the | ||
* Eclipse Public License v2.0 which accompanies this distribution, and is available at | ||
* https://www.eclipse.org/legal/epl-v20.html | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Copyright Contributors to the Zowe Project. | ||
*/ | ||
|
||
package org.zowe.apiml.caching.service.vsam; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
import org.zowe.apiml.caching.config.VsamConfig; | ||
import org.zowe.apiml.caching.model.KeyValue; | ||
import org.zowe.apiml.util.ClassOrDefaultProxyUtils; | ||
import org.zowe.apiml.zfile.*; | ||
|
||
import java.io.Closeable; | ||
import java.util.regex.Pattern; | ||
|
||
/** | ||
* ZFile wrapper providing convenience methods and implementing Closeable interface | ||
* | ||
* Creates a proxy of com.ibm.jzos.ZFileException and wraps it's methods | ||
* | ||
*/ | ||
|
||
@Slf4j | ||
public class VsamFile implements Closeable, ZFile { | ||
|
||
private ZFile zfile; | ||
private VsamConfig vsamConfig; | ||
private String options = "ab+,type=record"; | ||
private static final Pattern REGEX_CORRECT_FILENAME = Pattern.compile("^\\/\\/\\'.*'"); | ||
|
||
public VsamFile(VsamConfig config) { | ||
if (config == null) { | ||
throw new IllegalArgumentException("Cannot create VsamFile with null configuration"); | ||
} | ||
this.vsamConfig = config; | ||
try { | ||
this.zfile = openZfile(); | ||
} catch (ZFileException e) { | ||
throw new IllegalStateException("Failed to open VsamFile"); | ||
} | ||
} | ||
|
||
@Override | ||
public void close() { | ||
|
||
if (zfile != null) { | ||
try { | ||
zfile.close(); | ||
} catch (ZFileException e) { | ||
log.error("Closing ZFile failed"); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* This method writes a record to file and deletes it immediately. | ||
* Use this method on freshly created empty VSAM to write the fist record | ||
* and to verify that records can be written. | ||
* | ||
* Exceptions are thrown to give chance to the caller to react. | ||
* | ||
* @throws ZFileException | ||
* @throws VsamRecordException | ||
*/ | ||
public void warmUpVsamFile() throws ZFileException, VsamRecordException { | ||
|
||
log.info("Warming up the vsam file by writing and deleting a record"); | ||
|
||
log.info("VSAM file being used: {}", zfile.getActualFilename()); | ||
|
||
VsamRecord record = new VsamRecord(vsamConfig, "delete", new KeyValue("me", "novalue")); | ||
|
||
log.info("Writing Record: {}", record); | ||
zfile.write(record.getBytes()); | ||
|
||
boolean found = zfile.locate(record.getKeyBytes(), ZFileConstants.LOCATE_KEY_EQ); | ||
|
||
log.info("Test record for deletion found: {}", found); | ||
if (found) { | ||
byte[] recBuf = new byte[vsamConfig.getRecordLength()]; | ||
zfile.read(recBuf); //has to be read before update/delete | ||
zfile.delrec(); | ||
log.info("Test record deleted."); | ||
} | ||
|
||
} | ||
|
||
@SuppressWarnings({"squid:S1130", "squid:S1192"}) | ||
private ZFile openZfile() throws ZFileException { | ||
if (!REGEX_CORRECT_FILENAME.matcher(vsamConfig.getFileName()).find()) { | ||
throw new IllegalStateException("VsamFile does not exist"); | ||
} | ||
return ClassOrDefaultProxyUtils.createProxyByConstructor(ZFile.class, "com.ibm.jzos.ZFile", | ||
ZFileDummyImpl::new, | ||
new Class[] {String.class, String.class}, | ||
new Object[] {vsamConfig.getFileName(), options}, | ||
new ClassOrDefaultProxyUtils.ByMethodName<>( | ||
"com.ibm.jzos.ZFileException", ZFileException.class, | ||
"getFileName", "getMessage", "getErrnoMsg", "getErrno", "getErrno2", "getLastOp", "getAmrcBytes", | ||
"getAbendCode", "getAbendRc", "getFeedbackRc", "getFeedbackFtncd", "getFeedbackFdbk"), | ||
new ClassOrDefaultProxyUtils.ByMethodName<>( | ||
"com.ibm.jzos.RcException", RcException.class, | ||
"getMessage", "getRc"), | ||
new ClassOrDefaultProxyUtils.ByMethodName<>( | ||
"com.ibm.jzos.EnqueueException", EnqueueException.class, | ||
"getMessage", "getRc") | ||
); | ||
} | ||
|
||
@Override | ||
public void delrec() throws ZFileException { | ||
zfile.delrec(); | ||
} | ||
|
||
@Override | ||
public boolean locate(byte[] key, int options) throws ZFileException { | ||
return zfile.locate(key, options); | ||
} | ||
|
||
@Override | ||
public boolean locate(byte[] key, int offset, int length, int options) throws ZFileException { | ||
return zfile.locate(key, offset, length, options); | ||
} | ||
|
||
@Override | ||
public boolean locate(long recordNumberOrRBA, int options) throws ZFileException { | ||
return zfile.locate(recordNumberOrRBA, options); | ||
} | ||
|
||
@Override | ||
public int read(byte[] buf) throws ZFileException { | ||
return zfile.read(buf); | ||
} | ||
|
||
@Override | ||
public int read(byte[] buf, int offset, int len) throws ZFileException { | ||
return zfile.read(buf, offset, len); | ||
} | ||
|
||
@Override | ||
public int update(byte[] buf) throws ZFileException { | ||
return zfile.update(buf); | ||
} | ||
|
||
@Override | ||
public int update(byte[] buf, int offset, int length) throws ZFileException { | ||
return zfile.update(buf, offset, length); | ||
} | ||
|
||
@Override | ||
public void write(byte[] buf) throws ZFileException { | ||
zfile.write(buf); | ||
} | ||
|
||
@Override | ||
public void write(byte[] buf, int offset, int len) throws ZFileException { | ||
zfile.write(buf, offset, len); | ||
} | ||
|
||
@Override | ||
public String getActualFilename() { | ||
return zfile.getActualFilename(); | ||
} | ||
} |
44 changes: 44 additions & 0 deletions
44
caching-service/src/test/java/org/zowe/apiml/caching/service/vsam/VsamFileTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* | ||
* This program and the accompanying materials are made available under the terms of the | ||
* Eclipse Public License v2.0 which accompanies this distribution, and is available at | ||
* https://www.eclipse.org/legal/epl-v20.html | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Copyright Contributors to the Zowe Project. | ||
*/ | ||
|
||
package org.zowe.apiml.caching.service.vsam; | ||
|
||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.zowe.apiml.caching.config.VsamConfig; | ||
|
||
import static org.junit.jupiter.api.Assertions.*; | ||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.when; | ||
|
||
class VsamFileTest { | ||
|
||
VsamConfig config; | ||
|
||
@BeforeEach | ||
void prepareConfig() { | ||
config = mock(VsamConfig.class); | ||
} | ||
|
||
@Test | ||
void hasValidFileName() { | ||
when(config.getFileName()).thenReturn("//'DATASET.NAME'"); | ||
assertThrows(UnsupportedOperationException.class, () -> new VsamFile(config)); | ||
} | ||
|
||
@Test | ||
void hasInvalidFileName() { | ||
when(config.getFileName()).thenReturn("wrong"); | ||
Exception exception = assertThrows(IllegalStateException.class, | ||
() -> new VsamFile(config), | ||
"Expected exception is not IllegalStateException"); | ||
assertEquals("VsamFile does not exist", exception.getMessage()); | ||
} | ||
} |
Oops, something went wrong.