# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: marian.edu@acorn.ro-20210131101452-ui20dacrs58vsdlj # target_branch: sftp://medu@xfer.goldencode.com/opt/fwd/3821c/ # testament_sha1: f5f7eca50742231137f87677da03f7f60bdd4f38 # timestamp: 2021-02-01 15:22:55 +0200 # base_revision_id: ias@goldencode.com-20210129203239-6x21i9lmq9854bvj # # Begin patch === modified file 'src/com/goldencode/p2j/oo/core/Assert.java' --- src/com/goldencode/p2j/oo/core/Assert.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/core/Assert.java 2020-10-23 13:00:35 +0000 @@ -12,6 +12,7 @@ ** IsTrue. ** 003 IAS 20190923 Added implementation of additional methods ** 004 CA 20191024 Added method support levels and updated the class support level. +** 005 ME 20201023 Added implementation for isType, notType. */ /* @@ -1008,7 +1009,7 @@ final character _p2) { internalProcedure(Assert.class, "IsNull", new Block((Body) () -> { - AssertObject.isNull(_p1, new character("argument")); + AssertObject.isNull(_p1, _p2); })); } @@ -1071,7 +1072,7 @@ @LegacySignature(type = Type.METHOD, name = "IsPositive", parameters = { @LegacyParameter(name = "p1", type = "DECIMAL", mode = "INPUT"), @LegacyParameter(name = "p2", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public static void isPositive(final decimal _p1, final character _p2) { internalProcedure(Assert.class, "IsPositive", new Block((Body) () -> { @@ -1174,34 +1175,31 @@ @LegacySignature(type = Type.METHOD, name = "IsType", parameters = { @LegacyParameter(name = "p1", type = "HANDLE", mode = "INPUT"), @LegacyParameter(name = "p2", type = "OBJECT", qualified = "openedge.core.datatypeenum", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public static void isType(final handle _p1, final object _p2) { ObjectOps.load(Assert.class); - handle p1 = TypeFactory.initInput(_p1); - object p2 = TypeFactory.initInput(_p2); - - internalProcedure(Assert.class, "IsType", new Block()); + internalProcedure(Assert.class, "IsType", new Block((Body) () -> { + AssertObject.isType(_p1, _p2, new character("argument")); + })); } @LegacySignature(type = Type.METHOD, name = "IsType", parameters = { @LegacyParameter(name = "p1", type = "HANDLE", mode = "INPUT"), @LegacyParameter(name = "p2", type = "OBJECT", qualified = "openedge.core.datatypeenum", mode = "INPUT"), @LegacyParameter(name = "p3", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public static void isType(final handle _p1, final object _p2, final character _p3) { ObjectOps.load(Assert.class); - handle p1 = TypeFactory.initInput(_p1); - object p2 = TypeFactory.initInput(_p2); - character p3 = TypeFactory.initInput(_p3); - - internalProcedure(Assert.class, "IsType", new Block()); + internalProcedure(Assert.class, "IsType", new Block((Body) () -> { + AssertObject.isType(_p1, _p2, _p3); + })); } @LegacySignature(type = Type.METHOD, name = "IsType", parameters = { @@ -1303,7 +1301,7 @@ @LegacySignature(type = Type.METHOD, name = "IsZero", parameters = { @LegacyParameter(name = "p1", type = "INT64", mode = "INPUT"), @LegacyParameter(name = "p2", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public static void isZero(final int64 _p1, final character _p2) { ObjectOps.load(Assert.class); @@ -2156,7 +2154,7 @@ @LegacySignature(type = Type.METHOD, name = "NotNull", parameters = { @LegacyParameter(name = "p1", type = "HANDLE", mode = "INPUT"), @LegacyParameter(name = "p2", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public static void notNull(final handle _p1, final character _p2) { handle p1 = TypeFactory.initInput(_p1); @@ -2474,7 +2472,7 @@ @LegacySignature(type = Type.METHOD, name = "NotNullOrZero", parameters = { @LegacyParameter(name = "p1", type = "INTEGER", mode = "INPUT"), @LegacyParameter(name = "p2", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public static void notNullOrZero(final integer _p1, final character _p2) { internalProcedure(Assert.class, "NotNullOrZero", new Block((Body) () -> { @@ -2525,16 +2523,14 @@ @LegacyParameter(name = "p1", type = "HANDLE", mode = "INPUT"), @LegacyParameter(name = "p2", type = "OBJECT", qualified = "openedge.core.datatypeenum", mode = "INPUT"), @LegacyParameter(name = "p3", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public static void notType(final handle _p1, final object _p2, final character _p3) { - handle p1 = TypeFactory.initInput(_p1); - object p2 = TypeFactory.initInput(_p2); - character p3 = TypeFactory.initInput(_p3); - - internalProcedure(Assert.class, "NotType", new Block()); + internalProcedure(Assert.class, "NotType", new Block((Body) () -> { + AssertObject.notType(_p1, _p2, _p3); + })); } @LegacySignature(type = Type.METHOD, name = "NotType", parameters = { === modified file 'src/com/goldencode/p2j/oo/core/ByteBucket.java' --- src/com/goldencode/p2j/oo/core/ByteBucket.java 2021-01-13 15:36:44 +0000 +++ src/com/goldencode/p2j/oo/core/ByteBucket.java 2021-01-31 10:14:52 +0000 @@ -10,6 +10,8 @@ ** 003 CA 20200313 Fixed a typo in putBytes_1 LegacySignature annotation. ** 004 GES 20200429 Shifted to new legacy enum approach. ** 005 ME 20200604 Rewrite to match the 4GL implementation. +** 20201019 Always write at the end regardless of position set, check max size +** boundary (2G). ** 006 CA 20210113 Renamed clear() to clear_(), to follow NameConverter's rules. */ @@ -79,8 +81,6 @@ import java.util.*; -import org.apache.commons.lang3.*; - /** * Business logic (converted to Java from the 4GL source code * in OpenEdge/Core/ByteBucket.cls). @@ -100,14 +100,14 @@ /** The current position */ protected int64 position = TypeFactory.int64(0L); + /** The current write position, putBytes always seems to write at the end regardless of position set **/ + private long writePosition = 0L; + /** The bucket size (total number of bytes) */ protected int64 size = TypeFactory.int64(0L); - private integer initialNumRecs = TypeFactory.integer(3L); - private int currentDataIndex; - /** List of rows */ - protected LinkedList buckets = new LinkedList<>(); + protected LinkedList buckets = new LinkedList<>(); /** * Execute method @@ -176,7 +176,15 @@ public int64 getSize() { return function(this, "Size", int64.class, new Block((Body) () -> { - returnNormal(size); + // make sure size is not unknown (destroy), $GL BUG probably not checking for valid object + if (size.isUnknown()) + { + ErrorManager.recordOrThrowError(3135, "Invalid handle. Not initialized or points to a deleted object"); + } + else + { + returnNormal(size); + } })); } @@ -197,47 +205,66 @@ public void __core_ByteBucket_constructor__() { internalProcedure(this, "__core_ByteBucket_constructor__", new Block((Body) () -> { - __core_ByteBucket_constructor__(initialNumRecs); + __core_ByteBucket_constructor__(new int64(0)); })); } /** * Constructor. * - * @param _p1 the initial size of the memptrs that are held in the Bucket's array. - */ - @LegacySignature(type = Type.CONSTRUCTOR, parameters = { - @LegacyParameter(name = "p1", type = "INT64", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) - public void __core_ByteBucket_constructor__(final int64 _p1) - { - // default capacity sent as input ignored on 4GL implementation, deprecated - // since 11.7.0 - __core_ByteBucket_constructor__(initialNumRecs); - } - - /** - * Constructor. - * - * @param _p1 the initial size of the memptrs that are held in the Bucket's array. - */ - @LegacySignature(type = Type.CONSTRUCTOR, parameters = { - @LegacyParameter(name = "p1", type = "INTEGER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) - public void __core_ByteBucket_constructor__(final integer _p1) - { - - integer p1 = TypeFactory.initInput(_p1); - + * @param defaultCapacity the default capacity of the memptrs that are held in the Bucket's array. + */ + @LegacySignature(type = Type.CONSTRUCTOR, parameters = { + @LegacyParameter(name = "defaultCapacity", type = "INT64", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void __core_ByteBucket_constructor__(final int64 _defaultCapacity) + { + int64 defaultCapacity = TypeFactory.initInput(_defaultCapacity); + internalProcedure(this, "__core_ByteBucket_constructor__", new Block((Body) () -> { __lang_BaseObject_constructor__(); - Assert.isPositive(p1, new character("Initial size")); - - position.assign(1); - defaultCapacity.assign(MAX_BYTES_PER_ROW); - initialNumRecs.assign(p1); - currentDataIndex = 0; + // just throw a 'matching' error for now until implementation is using the new MemoryOutputStream + if (defaultCapacity.isUnknown() || defaultCapacity.longValue() < 0) { + ErrorManager.recordOrThrowError(18193, "Invalid value specified for parameter 'value' of method or constructor 'Progress.IO.MemoryOutputStream'."); + } + + if (defaultCapacity.longValue() != 0 ) { + if (defaultCapacity.longValue() > Integer.MAX_VALUE ) { + ErrorManager.recordOrThrowError(0, "The initial stream size cannot be greater than 2GB"); + } + + // pre-allocate memory??? + for (int i = 0; i < (int) (defaultCapacity.longValue() / MAX_BYTES_PER_ROW); i++) + { + buckets.add(new byte[MAX_BYTES_PER_ROW]); + } + } + + this.defaultCapacity.assign(defaultCapacity); + this.position.assign(1); + })); + + + } + + /** + * Constructor. + * + * @param initialSize the initial size of the memptrs that are held in the Bucket's array. + */ + @LegacySignature(type = Type.CONSTRUCTOR, parameters = { + @LegacyParameter(name = "initialSize", type = "INTEGER", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void __core_ByteBucket_constructor__(final integer _initialSize) + { + + integer initialSize = TypeFactory.initInput(_initialSize); + + internalProcedure(this, "__core_ByteBucket_constructor__", new Block((Body) () -> { + __core_ByteBucket_constructor__(); + + Assert.isPositive(initialSize, new character("Initial size")); })); } @@ -248,13 +275,14 @@ * @param _p2 the initial number of buckets (not used in the current implementation). */ @LegacySignature(type = Type.CONSTRUCTOR, parameters = { - @LegacyParameter(name = "p1", type = "INTEGER", mode = "INPUT"), - @LegacyParameter(name = "p2", type = "INT64", mode = "INPUT") }) + @LegacyParameter(name = "initialSize", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "defaultCapacity", type = "INT64", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) - public void __core_ByteBucket_constructor__(final integer p1, final int64 p2) + public void __core_ByteBucket_constructor__(final integer initialSize, final int64 defaultCapacity) { // default capacity input parameter ignored on 4GL, deprecated since 11.7.0 - __core_ByteBucket_constructor__(p1); + // in OE12.2 initial size (number of rows) is not used anymore but default capacity (bytes) is used instead + __core_ByteBucket_constructor__(defaultCapacity); } /** @@ -280,45 +308,33 @@ internalProcedure(this, "Clear", new Block((Body) () -> { this.position.assign(1); this.size.assign(0); - currentDataIndex = 0; - - for (BucketEntry bucket : buckets) - { - bucket.bytesWritten = 0; - } })); } /** - * Debug method to dump out current RAW bytes into numbered files. - * Files are named bytebucket-memptr-<number>.bin + * Debug method to dump out current RAW bytes into a file. + * The file is saved in session temporary folder as "bytebucket-memptr-<object_id>.bin" */ @LegacySignature(type = Type.METHOD, name = "Debug") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void debug() { internalProcedure(this, "Debug", new Block((Body) () -> { - String folderPath = EnvironmentOps.getTempDirectory().getValue(); - character fullPath = TypeFactory.character(); - - for (int i = 0; i < buckets.size(); i++) - { - BucketEntry bucket = buckets.get(i); - - memptr ptr = new memptr(Arrays.copyOf(bucket.data, bucket.bytesWritten)); - fullPath.assign(String.format("%sbytebucket-memptr-%d.bin", folderPath, i + 1)); - - try - { - new LobCopy(new SourceLob(ptr), new TargetLobFile(fullPath)).run(); - } - finally - { - ptr.setLength(0); - } - } - + String debugPath = String.format("%sbytebucket-memptr-%d.bin", + EnvironmentOps.getTempDirectory().getValue(), + handle.resourceId(ObjectOps.asResource(this))); + memptr ptr = getBytes().ref().getValue(); + + try + { + new LobCopy(new SourceLob(ptr), new TargetLobFile(debugPath)).run(); + } + finally + { + ptr.setLength(0); + } + })); } @@ -332,8 +348,7 @@ { internalProcedure(this, "Destroy", new Block((Body) () -> { this.position.assign(1); - this.size.assign(0); - currentDataIndex = 0; + this.size.setUnknown(); buckets.clear(); })); @@ -373,23 +388,27 @@ int64 p = TypeFactory.initInput(_pos); return function(this, "GetByte", integer.class, new Block((Body) () -> { - Assert.isPositive(p, new character("Start position")); - long pos = p.longValue(); - - int nbucket = (int) ((pos - 1) / defaultCapacity.longValue()); - int offset = (int) ((pos - 1) % defaultCapacity.longValue()); - - if (nbucket < buckets.size()) - { - BucketEntry bucket = buckets.get(nbucket); - - if (offset < bucket.bytesWritten) - returnNormal(new integer(bucket.data[offset])); - - // data in 4GL blob field is truncated, read pass length returns unknown - returnNormal(new integer()); + if (!p.isUnknown()) { + long pos = p.longValue(); + + if (pos < 1) + { + BinaryData.genIndexError(); + } + else if (pos <= size.longValue()) + { + int nbucket = (int) ((pos - 1) / MAX_BYTES_PER_ROW); + int offset = (int) ((pos - 1) % MAX_BYTES_PER_ROW); + + if (nbucket < buckets.size()) + { + byte[] bucket = buckets.get(nbucket); + + returnNormal(new integer(bucket[offset] & 0xFF)); + } + } } - + returnNormal(new integer(0)); })); } @@ -441,7 +460,7 @@ int64 size = TypeFactory.initInput(_size); return function(this, "GetBytes", object.class, new Block((Body) () -> { - if (CompareOps._isEqual(size, 0) || CompareOps._isEqual(getSize(), 0)) + if (getSize().longValue() == 0 || size.longValue() == 0) { returnNormal(Memptr.getEmpty()); } @@ -507,7 +526,7 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public longchar getString() { - return getString(new int64(1), this.size); + return getString(new int64(1), this.getSize()); } /** @@ -593,7 +612,7 @@ Assert.isPositive(pos, new character("Start position")); Assert.isZeroOrPositive(size, new character("Slice size")); - if (StringUtils.isBlank(targetCP.getValue())) + if (TextOps.isEmpty(targetCP)) targetCP.assign("UTF-8"); longchar lc = TypeFactory.longchar(); @@ -604,7 +623,7 @@ returnNormal(lc); } - if (StringUtils.isBlank(sourceCP.getValue())) + if (TextOps.isEmpty(sourceCP)) sourceCP.assign("UTF-8"); memptr ptr = TypeFactory.memptr(); @@ -639,7 +658,6 @@ { internalProcedure(this, "Initialize", new Block((Body) () -> { clear_(); - resize(initialNumRecs); })); } @@ -673,7 +691,6 @@ public static object instance(final int64 _p1) { int64 p1 = TypeFactory.initInput(_p1); - ObjectOps.load(ByteBucket.class); return function(ByteBucket.class, "Instance", object.class, new Block((Body) () -> { object bb = ObjectOps.newInstance(ByteBucket.class, "I", p1); bb.ref().initialize(); @@ -697,29 +714,13 @@ { integer p1 = TypeFactory.initInput(_p1); int64 p2 = TypeFactory.initInput(_p2); - ObjectOps.load(ByteBucket.class); return function(ByteBucket.class, "Instance", object.class, new Block((Body) () -> { - Assert.isPositive(p1, new character("Initial size")); object bb = ObjectOps.newInstance(ByteBucket.class, "II", p1, p2); bb.ref().initialize(); returnNormal(bb); })); } - private static void mergeBuckets(final ByteBucket source, final ByteBucket target) - { - int total = source.getSize().intValue(); - - if (total == 0) - { - return; - } - - source.buckets.stream().filter(b -> b.bytesWritten > 0) - .forEachOrdered(b -> target.writeBytes(b.data, b.bytesWritten)); - - } - /** * Copies all of the bytes from a ByteBucket instance into this bucket. * @@ -728,14 +729,27 @@ @LegacySignature(type = Type.METHOD, name = "PutBytes", parameters = { @LegacyParameter(name = "data", type = "OBJECT", qualified = "openedge.core.bytebucket", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) - public void putBytes(final object data) + public void putBytes(final object _data) { + object data = TypeFactory.initInput(_data); + internalProcedure(this, "PutBytes", new Block((Body) () -> { Assert.notNull(data, new character("Input data")); - if (data.getSize() > 0) + ByteBucket bbucket = data.ref(); + long size = bbucket.getSize().longValue(); + + if (size > 0) { - mergeBuckets(data.ref(), this); + int endBucket = (int) (size / MAX_BYTES_PER_ROW); + int endOffset = (int) (size % MAX_BYTES_PER_ROW); + + for (int i = 0; i <= endBucket; i++) + { + byte[] bucket = bbucket.buckets.get(i); + + writeBytes(bucket, i < endBucket ? MAX_BYTES_PER_ROW : endOffset); + } } })); } @@ -866,10 +880,10 @@ character targetCP = TypeFactory.initInput(_targetCP); internalProcedure(this, "PutString", new Block((Body) () -> { - if (!data.isUnknown() && StringUtils.isEmpty(data.getValue())) + if (TextOps.isEmpty(data)) return; - if (targetCP.isUnknown() || StringUtils.isEmpty(targetCP.getValue())) + if (TextOps.isEmpty(targetCP)) { targetCP.assign("UTF-8"); } @@ -916,39 +930,7 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void resize(final integer _p1) { - integer psize = TypeFactory.initInput(_p1); - - internalProcedure(this, "Resize", new Block((Body) () -> { - if (!psize.isUnknown()) - { - if (psize.intValue() > currentDataIndex) - { - for (int i = currentDataIndex + 1; i < psize.intValue(); i++) - { - if (buckets.size() < i) - { - buckets.add(new BucketEntry()); - } - } - - } - else if (!defaultCapacity.isUnknown()) - { - - while (buckets.size() > Math.ceil(psize.longValue() / defaultCapacity.longValue())) - { - BucketEntry bucket = buckets.getLast(); - - if (bucket.bytesWritten != 0) - break; - - buckets.remove(bucket); - } - } - } - - currentDataIndex = psize.isUnknown() ? 0 : psize.intValue() - 1; - })); + // no-op in OE12.2 } /** @@ -962,11 +944,7 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void resizeArray(final integer _p1) { - integer p1 = TypeFactory.initInput(_p1); - - internalProcedure(this, "ResizeArray", new Block((Body) () -> { - resize(p1); - })); + // no-op in oe12.2 } /** @@ -984,17 +962,20 @@ long pos = p.longValue(); long bytesLeft = data.lengthOf(); int putAt = 0; - int nbucket = (int) ((pos - 1) / defaultCapacity.longValue()); - int offset = (int) ((pos - 1) % defaultCapacity.longValue()); + int nbucket = (int) ((pos - 1) / MAX_BYTES_PER_ROW); + int offset = (int) ((pos - 1) % MAX_BYTES_PER_ROW); + int endBucket = (int) ((size.longValue()) / MAX_BYTES_PER_ROW); + int endOffset = (int) ((size.longValue()) % MAX_BYTES_PER_ROW); + - for (int i = nbucket; i <= currentDataIndex; i++) + for (int i = nbucket; i <= endBucket; i++) { - BucketEntry bucket = buckets.get(i); - int numBytes = (int) Math.min(bucket.bytesWritten - offset, bytesLeft); + byte[] bucket = buckets.get(i); + int numBytes = (int) Math.min((i == endBucket ? endOffset : MAX_BYTES_PER_ROW) - offset, bytesLeft); if (numBytes > 0) { - data.write(true, Arrays.copyOfRange(bucket.data, offset, offset + numBytes), putAt, + data.write(true, Arrays.copyOfRange(bucket, offset, offset + numBytes), putAt, false); offset = 0; @@ -1017,67 +998,82 @@ { long bytesLeft = ptr.lengthOf(); - long startPos = 0; + long bytesWritten = 0; - while (bytesLeft > 0) + while (bytesLeft > bytesWritten) { long numBytes = Math.min(bytesLeft, Integer.MAX_VALUE); - writeBytes(ptr.asByteArray(startPos, numBytes), (int) numBytes); - startPos += numBytes; - bytesLeft -= numBytes; + numBytes = writeBytes(ptr.asByteArray(bytesWritten, numBytes), (int) numBytes); + bytesWritten += numBytes; } + + this.position.assign(this.position.longValue() + bytesWritten); } - private void writeBytes(byte[] data, int len) + /** + * Write the content of byte array. + * + * The method updates the size but not the position because putBytes form ByteBucket does not + * change the current position. + * + * @param data the byte array data + * @param len the length of data to write + * + * @return the number of bytes written + */ + private int writeBytes(byte[] data, int len) { int bytesLeft = Math.min(data.length, len); - int startPos = 0; - - while (bytesLeft > 0) - { - BucketEntry bucket; - - if (buckets.size() > currentDataIndex) - { - bucket = buckets.get(currentDataIndex); - } - else - { - bucket = new BucketEntry(); - buckets.add(bucket); - } - - int numBytes = Math.min(MAX_BYTES_PER_ROW - bucket.bytesWritten, bytesLeft); - bytesLeft -= numBytes; - - if (numBytes > 0) - { - System.arraycopy(data, startPos, bucket.data, bucket.bytesWritten, numBytes); - bucket.bytesWritten += numBytes; - startPos += numBytes; - position.assign(this.position.longValue() + numBytes); - size.assign(this.size.longValue() + numBytes); - } - - if (bucket.bytesWritten == MAX_BYTES_PER_ROW) - { - currentDataIndex++; - } - } - } - - private static class BucketEntry - { - public byte[] data; - public int bytesWritten; - - BucketEntry() - { - data = new byte[MAX_BYTES_PER_ROW]; - bytesWritten = 0; - - } - } + int bytesWritten = 0; + int crtBucket = (int) (writePosition / MAX_BYTES_PER_ROW); + int endBucket = (int) ((size.longValue()) / MAX_BYTES_PER_ROW); + int endOffset = (int) ((size.longValue()) % MAX_BYTES_PER_ROW); + + if (writePosition + bytesLeft > Integer.MAX_VALUE) + { + ErrorManager.recordOrThrowError(0, + "Cannot expand memory allocation because it exceeds the limit", false); + return 0; + + } + else + { + + while (bytesLeft > 0) + { + byte[] bucket; + + if (buckets.size() > crtBucket) + { + bucket = buckets.get(crtBucket); + } + else + { + bucket = new byte[MAX_BYTES_PER_ROW]; + buckets.add(bucket); + } + + int pos = crtBucket == endBucket ? endOffset : 0; + int numBytes = Math.min(MAX_BYTES_PER_ROW - pos, bytesLeft); + + bytesLeft -= numBytes; + + if (numBytes > 0) + { + System.arraycopy(data, bytesWritten, bucket, pos, numBytes); + bytesWritten += numBytes; + } + + crtBucket++; + } + + writePosition += bytesWritten; + size.assign(this.size.longValue() + bytesWritten); + + return bytesWritten; + } + } + } === modified file 'src/com/goldencode/p2j/oo/core/assertion/AssertObject.java' --- src/com/goldencode/p2j/oo/core/assertion/AssertObject.java 2020-04-15 21:19:33 +0000 +++ src/com/goldencode/p2j/oo/core/assertion/AssertObject.java 2020-10-23 13:00:35 +0000 @@ -8,6 +8,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 ME 20200324 Created the first version, by converting the legacy skeleton .cls file and ** using that output. +** 002 ME 20201023 Added implementation for isType, notType. */ /* @@ -564,7 +565,7 @@ @LegacyParameter(name = "p1", type = "HANDLE", mode = "INPUT"), @LegacyParameter(name = "p2", type = "OBJECT", qualified = "openedge.core.datatypeenum", mode = "INPUT"), @LegacyParameter(name = "p3", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public static void isType(final handle _p1, final object _p2, final character _p3) @@ -574,7 +575,14 @@ object p2 = TypeFactory.initInput(_p2); character p3 = TypeFactory.initInput(_p3); - internalProcedure(AssertObject.class, "IsType", new Block()); + internalProcedure(AssertObject.class, "IsType", new Block((Body) () -> { + Assert.notNull(p1, p3); + notNull(p2, new character("Check DataType")); + + if (!p1.isType(p2.ref().toLegacyString().getValue())) + returnError(ObjectOps.newInstance(AssertionFailedError.class, "II", + substitute("&1 is not of type &2", p3, p2), 0)); + })); } @LegacySignature(type = Type.METHOD, name = "IsType", parameters = { @@ -593,7 +601,7 @@ @LegacyParameter(name = "p1", type = "HANDLE", mode = "INPUT"), @LegacyParameter(name = "p2", type = "OBJECT", qualified = "openedge.core.datatypeenum", mode = "INPUT"), @LegacyParameter(name = "p3", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public static void notType(final handle _p1, final object _p2, final character _p3) @@ -603,7 +611,14 @@ object p2 = TypeFactory.initInput(_p2); character p3 = TypeFactory.initInput(_p3); - internalProcedure(AssertObject.class, "NotType", new Block()); + internalProcedure(AssertObject.class, "NotType", new Block((Body) () -> { + Assert.notNull(p1, p3); + notNull(p2, new character("Check DataType")); + + if (p1.isType(p2.ref().toLegacyString().getValue())) + returnError(ObjectOps.newInstance(AssertionFailedError.class, "II", + substitute("&1 cannot be of type &2", p3, p2), 0)); + })); } @LegacySignature(type = Type.METHOD, name = "NotType", parameters = { @@ -681,28 +696,42 @@ @LegacySignature(type = Type.METHOD, name = "IsSerializable", parameters = { @LegacyParameter(name = "p1", type = "OBJECT", qualified = "progress.lang.object", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public static void isSerializable( final object _p1) { ObjectOps.load(AssertObject.class); object p1 = TypeFactory.initInput(_p1); - internalProcedure(AssertObject.class, "IsSerializable", new Block()); - // TODO: add serializable in progress.lang.class (LegacyClass) + internalProcedure(AssertObject.class, "IsSerializable", new Block((Body) () -> { + Assert.notNull(p1, new character("argument")); + + object cls = LegacyClass.getLegacyClass(p1); + + if (!cls.ref().isSerializable().booleanValue()) + returnError(ObjectOps.newInstance(AssertionFailedError.class, "II", + substitute("Object &1 (of type &2) is not serializable", p1.ref().toLegacyString(), cls.ref().getTypeName()), 0)); + })); } @LegacySignature(type = Type.METHOD, name = "NotSerializable", parameters = { @LegacyParameter(name = "p1", type = "OBJECT", qualified = "progress.lang.object", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public static void notSerializable( final object _p1) { ObjectOps.load(AssertObject.class); object p1 = TypeFactory.initInput(_p1); - internalProcedure(AssertObject.class, "NotSerializable", new Block()); - // TODO: add serializable in progress.lang.class (LegacyClass) + internalProcedure(AssertObject.class, "NotSerializable", new Block((Body) () -> { + Assert.notNull(p1, new character("argument")); + + object cls = LegacyClass.getLegacyClass(p1); + + if (cls.ref().isSerializable().booleanValue()) + returnError(ObjectOps.newInstance(AssertionFailedError.class, "II", + substitute("Object &1 (of type &2) is serializable", p1.ref().toLegacyString(), cls.ref().getTypeName()), 0)); + })); } } === modified file 'src/com/goldencode/p2j/oo/core/collections/AbstractTtcollection.java' --- src/com/goldencode/p2j/oo/core/collections/AbstractTtcollection.java 2021-01-13 15:36:44 +0000 +++ src/com/goldencode/p2j/oo/core/collections/AbstractTtcollection.java 2021-01-31 10:14:52 +0000 @@ -8,6 +8,7 @@ ** 001 ME 20200514 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20210113 Renamed Iiterator.next to Iiterator.next_, to follow NameConverter's rules. ** 20210113 Renamed clear() to clear_(), to follow NameConverter's rules. +** 003 ME 20210128 Keep only the default 4GL temp-table implementation. */ /* @@ -68,8 +69,6 @@ import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; -import edu.emory.mathcs.backport.java.util.Arrays; - import com.goldencode.p2j.oo.core.Assert; import com.goldencode.p2j.oo.core.collections.Icollection; import com.goldencode.p2j.oo.lang.*; @@ -79,10 +78,6 @@ import static com.goldencode.p2j.util.BlockManager.*; import static com.goldencode.p2j.util.InternalEntry.Type; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; - /** * Business logic (converted to Java from the 4GL source code * in OpenEdge/Core/Collections/AbstractTTCollection.cls). @@ -98,8 +93,6 @@ private handle fieldHandle = TypeFactory.handle(); private handle queryHandle = TypeFactory.handle(); - private Collection> objects; - public void __core_collections_AbstractTtcollection_execute__() { externalProcedure(AbstractTtcollection.class, AbstractTtcollection.this, @@ -113,11 +106,9 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public integer getSize() { - return function(AbstractTtcollection.class, this, "Size", integer.class, - new Block((Body) () -> - { - returnNormal(size); - })); + return function(this, "Size", integer.class, new Block((Body) () -> { + returnNormal(size); + })); } @LegacySignature(type = Type.CONSTRUCTOR) @@ -128,8 +119,6 @@ "__core_collections_AbstractTtcollection_constructor__", new Block((Body) () -> { __lang_BaseObject_constructor__(); - // use a java collection by default - objects = new ArrayList>(); })); } @@ -157,13 +146,9 @@ final character _p2) { internalProcedure(AbstractTtcollection.class, this, - "__core_collections_AbstractTtcollection_constructor__", new Block((Body) () -> - { - __core_collections_AbstractTtcollection_constructor__(_p1, - _p1.isType(LegacyResource.TEMP_TABLE) - ? _p1.unwrapTempTable().defaultBufferHandle().unwrapBuffer() - .bufferField(_p2) - : new handle()); + "__core_collections_AbstractTtcollection_constructor__", new Block((Body) () -> { + __core_collections_AbstractTtcollection_constructor__(_p1, _p1.unwrapTempTable() + .defaultBufferHandle().unwrapBuffer().bufferField(_p2)); })); } @@ -183,18 +168,8 @@ __lang_BaseObject_constructor__(); size.assign(0); - // default 4GL temp-table implementation - if (p1.isType(LegacyResource.TEMP_TABLE)) - { - tableHandle.assign(p1); - fieldHandle.assign(p2); - objects = Collections.EMPTY_LIST; - } - // java map implementation - else - { - objects = new ArrayList>(); - } + tableHandle.assign(p1.unwrapTempTable()); + fieldHandle.assign(p2); })); } @@ -217,35 +192,23 @@ { object p1 = TypeFactory.initInput(_p1); - return function(AbstractTtcollection.class, this, "Add", logical.class, - new Block((Body) () -> - { - boolean result = false; - - if (p1._isValid()) - { - if (objects == Collections.EMPTY_LIST) - { - Buffer buffer = tableHandle.unwrapTempTable().defaultBufferHandle() - .unwrapBuffer(); - buffer.bufferCreate(); - fieldHandle.unwrapBufferField().changeValue(p1); - buffer.bufferRelease(); - - result = true; - } - else - { - result = objects.add(p1); - } - } - - if (result) - size.assign(size.intValue() + 1); - - returnNormal(result); - - })); + return function(this, "Add", logical.class, new Block((Body) () -> { + + if (p1._isValid()) + { + Buffer buffer = tableHandle.unwrapTempTable().defaultBufferHandle().unwrapBuffer(); + buffer.bufferCreate(); + fieldHandle.unwrapBufferField().changeValue(p1); + buffer.bufferRelease(); + + size.assign(size.intValue() + 1); + + returnNormal(true); + } + + returnNormal(false); + + })); } @LegacySignature(type = Type.METHOD, name = "AddArray", parameters = { @@ -253,30 +216,19 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public logical addArray(final object[] _p1) { - object[] p1[] = new object[][] { TypeFactory.initInput(_p1) }; - - return function(AbstractTtcollection.class, this, "AddArray", logical.class, - new Block((Body) () -> - { - if (p1[0].length > 0) - { - if (objects == Collections.EMPTY_LIST) - { - for (int i = 0; i < p1.length; i++) - { - add(p1[0][i]); - } - } - else - { - objects.addAll(Arrays.asList(p1[0])); - - size.assign(size.intValue() + p1[0].length); - } - } - - returnNormal(true); - })); + object p1[] = TypeFactory.initInput(_p1); + + return function(this, "AddArray", logical.class, new Block((Body) () -> { + if (p1.length > 0) + { + for (int i = 0; i < p1.length; i++) + { + add(p1[i]); + } + } + + returnNormal(true); + })); } @LegacySignature(type = Type.METHOD, name = "AddAll", parameters = { @@ -286,27 +238,25 @@ { object p1 = TypeFactory.initInput(_p1); - return function(AbstractTtcollection.class, this, "AddAll", logical.class, - new Block((Body) () -> - { - if (objects == Collections.EMPTY_LIST && getLegacyClass().ref() - .legacyEquals(p1.ref().getLegacyClass()).booleanValue()) - { - p1.ref().toTable(new TableParameter(tableHandle, true)); - size.assign(size.intValue() + p1.ref().getSize().intValue()); - } - else - { - Iiterator it = p1.ref().iterator().ref(); - - while (it.hasNext().booleanValue()) - { - add(it.next_()); - } - } - - returnNormal(true); - })); + return function(this, "AddAll", logical.class, new Block((Body) () -> { + if (getLegacyClass().ref() + .legacyEquals(p1.ref().getLegacyClass()).booleanValue()) + { + p1.ref().toTable(new TableParameter(tableHandle, true)); + size.assign(size.intValue() + p1.ref().getSize().intValue()); + } + else + { + Iiterator it = p1.ref().iterator().ref(); + + while (it.hasNext().booleanValue()) + { + add(it.next_()); + } + } + + returnNormal(true); + })); } @LegacySignature(type = Type.METHOD, name = "Clear") @@ -315,15 +265,7 @@ { internalProcedure(AbstractTtcollection.class, this, "Clear", new Block((Body) () -> { - if (objects == Collections.EMPTY_LIST) - { - tableHandle.unwrapTempTable().deleteAll(); - } - else - { - objects.clear(); - } - + tableHandle.unwrapTempTable().deleteAll(); size.assign(0); })); } @@ -335,20 +277,11 @@ { object p1 = TypeFactory.initInput(_p1); - return function(AbstractTtcollection.class, this, "Contains", logical.class, - new Block((Body) () -> - { - if (objects == Collections.EMPTY_LIST) - { - findBufferUseObject(p1); - returnNormal(tableHandle.unwrapTempTable().defaultBufferHandle() - .unwrapBuffer().available()); - } - else - { - returnNormal(objects.contains(p1)); - } - })); + return function(this, "Contains", logical.class, new Block((Body) () -> { + findBufferUseObject(p1); + returnNormal(tableHandle.unwrapTempTable().defaultBufferHandle().unwrapBuffer() + .available()); + })); } @LegacySignature(type = Type.METHOD, name = "ContainsAll", parameters = { @@ -358,72 +291,50 @@ { object p1 = TypeFactory.initInput(_p1); - return function(AbstractTtcollection.class, this, "ContainsAll", logical.class, - new Block((Body) () -> - { - Assert.notNull(p1, new character("Collection to check")); - - if (p1.ref().isEmpty().booleanValue()) - returnNormal(true); - - // this is handled like a set not collection - if (p1.ref().getSize().intValue() > size.intValue()) - returnNormal(false); - - Iiterator it = p1.ref().iterator().ref(); - - while (it.hasNext().booleanValue()) - { - if (!contains(it.next_()).booleanValue()) - returnNormal(false); - } - - returnNormal(true); - })); + return function(this, "ContainsAll", logical.class, new Block((Body) () -> { + Assert.notNull(p1, new character("Collection to check")); + + if (p1.ref().isEmpty().booleanValue()) + returnNormal(true); + + // this is handled like a set not collection + if (p1.ref().getSize().intValue() > size.intValue()) + returnNormal(false); + + Iiterator it = p1.ref().iterator().ref(); + + while (it.hasNext().booleanValue()) + { + if (!contains(it.next_()).booleanValue()) + returnNormal(false); + } + + returnNormal(true); + })); } @LegacySignature(type = Type.METHOD, name = "Iterator", qualified = "openedge.core.collections.iiterator") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object iterator() { - return function(AbstractTtcollection.class, this, "Iterator", object.class, - new Block((Body) () -> - { - if (objects == Collections.EMPTY_LIST) - { - returnNormal(ObjectOps.newInstance(LegacyIterator.class, "III", - new object(this), tableHandle, fieldHandle.unwrap().name())); - } - else - { - returnNormal(ObjectOps.newInstance(LegacyIterator.class, "III", - new object(this), new handle(new TransparentWrapper(objects)), "")); - } - - })); + return function(this, "Iterator", object.class, new Block((Body) () -> { + returnNormal(ObjectOps.newInstance(LegacyIterator.class, "III", new object(this), + tableHandle, fieldHandle.unwrap().name())); + })); } @LegacySignature(type = Type.METHOD, name = "IsEmpty") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public logical isEmpty() { - return function(AbstractTtcollection.class, this, "IsEmpty", logical.class, - new Block((Body) () -> - { - if (objects == Collections.EMPTY_LIST) - { - returnNormal(!tableHandle.unwrapTempTable().hasRecords().booleanValue()); - } - else - { - returnNormal(objects.isEmpty()); - } - })); + return function(this, "IsEmpty", logical.class, new Block((Body) () -> { + returnNormal(!tableHandle.unwrapTempTable().hasRecords().booleanValue()); + })); } @LegacySignature(type = Type.METHOD, name = "ToTable", parameters = { @LegacyParameter(name = "p1", type = "HANDLE", mode = "OUTPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_PARTIAL) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void toTable(final TableParameter _p1) { handle p1 = new handle(); @@ -433,16 +344,8 @@ TypeFactory.initOutput(p1); }, (Body) () -> { - if (objects == Collections.EMPTY_LIST) - { - TemporaryBuffer.createDynamicTable(_p1, p1, false, true); - p1.assign(tableHandle); - } - // TODO: create table from collection - else - { - - } + TemporaryBuffer.createDynamicTable(_p1, p1, false, true); + p1.assign(tableHandle); })); } @@ -453,37 +356,25 @@ { object p1 = TypeFactory.initInput(_p1); - return function(AbstractTtcollection.class, this, "Remove", logical.class, - new Block((Body) () -> + return function(this, "Remove", logical.class, new Block((Body) () -> { + boolean result = false; + + if (p1._isValid()) + { + findBufferUseObject(p1); + Buffer buffer = tableHandle.unwrapTempTable().defaultBufferHandle().unwrapBuffer(); + if (buffer._available()) { - boolean result = false; - - if (p1._isValid()) - { - if (objects == Collections.EMPTY_LIST) - { - findBufferUseObject(p1); - Buffer buffer = tableHandle.unwrapTempTable().defaultBufferHandle() - .unwrapBuffer(); - if (buffer._available()) - { - buffer.deleteRecord(); - result = true; - } - - } - else - { - result = objects.remove(p1); - } - } - - if (result) - size.assign(size.intValue() - 1); - - returnNormal(result); - - })); + buffer.deleteRecord(); + result = true; + } + } + + if (result) + size.assign(size.intValue() - 1); + + returnNormal(result); + })); } @LegacySignature(type = Type.METHOD, name = "RemoveAll", parameters = { @@ -493,21 +384,19 @@ { object p1 = TypeFactory.initInput(_p1); - return function(AbstractTtcollection.class, this, "RemoveAll", logical.class, - new Block((Body) () -> - { - boolean result = false; - Iiterator it = p1.ref().iterator().ref(); - - while (it.hasNext().booleanValue()) - { - object obj = it.next_(); - while (remove(obj).booleanValue()) - result = true; - } - - returnNormal(result); - })); + return function(this, "RemoveAll", logical.class, new Block((Body) () -> { + boolean result = false; + Iiterator it = p1.ref().iterator().ref(); + + while (it.hasNext().booleanValue()) + { + object obj = it.next_(); + while (remove(obj).booleanValue()) + result = true; + } + + returnNormal(result); + })); } @LegacySignature(type = Type.METHOD, name = "RetainAll", parameters = { @@ -517,57 +406,47 @@ { object p1 = TypeFactory.initInput(_p1); - return function(AbstractTtcollection.class, this, "RetainAll", logical.class, - new Block((Body) () -> - { - boolean result = false; - Iiterator it = iterator().ref(); - - while (it.hasNext().booleanValue()) - { - object obj = it.next_(); - - if (!p1.ref().contains(obj).booleanValue()) - { - while (remove(obj).booleanValue()) - result = true; - } - } - - returnNormal(result); - })); + return function(this, "RetainAll", logical.class, new Block((Body) () -> { + boolean result = false; + Iiterator it = iterator().ref(); + + while (it.hasNext().booleanValue()) + { + object obj = it.next_(); + + if (!p1.ref().contains(obj).booleanValue()) + { + while (remove(obj).booleanValue()) + result = true; + } + } + + returnNormal(result); + })); } @LegacySignature(type = Type.METHOD, name = "ToArray", extent = -1, qualified = "progress.lang.object") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object[] toArray() { - return extentFunction(AbstractTtcollection.class, this, "ToArray", object.class, - new Block((Body) () -> - { - if (objects == Collections.EMPTY_LIST) - { - if (isEmpty().booleanValue()) - returnExtentNormal(new object[0]); - else - { - object oArr[] = TypeFactory - .objectExtent(getSize().intValue(), BaseObject.class); - Iiterator it = iterator().ref(); - int i = 0; + return extentFunction(this, "ToArray", object.class, new Block((Body) () -> { + + if (isEmpty().booleanValue()) + returnExtentNormal(new object[0]); + else + { + object oArr[] = TypeFactory + .objectExtent(getSize().intValue(), BaseObject.class); + Iiterator it = iterator().ref(); + int i = 0; - while (it.hasNext().booleanValue()) - { - oArr[i++].assign(it.next_()); - } - returnExtentNormal(oArr); - } - } - else - { - returnExtentNormal(objects.toArray(new object[objects.size()])); - } - })); + while (it.hasNext().booleanValue()) + { + oArr[i++].assign(it.next_()); + } + returnExtentNormal(oArr); + } + })); } @LegacySignature(type = Type.METHOD, name = "FindBufferUseObject", parameters = { @@ -579,14 +458,11 @@ @Override public object clone() { - return function(AbstractTtcollection.class, this, "Clone", object.class, - new Block((Body) () -> - { - object clone = ObjectOps - .newInstance(AbstractTtcollection.class); - cloneElements(clone); - returnNormal(clone); - })); + return function(this, "Clone", object.class, new Block((Body) () -> { + object clone = ObjectOps.newInstance(getClass()); + cloneElements(clone); + returnNormal(clone); + })); } @LegacySignature(type = Type.METHOD, name = "CloneElements", parameters = { @@ -610,27 +486,15 @@ { internalProcedure(AbstractTtcollection.class, this, "Resize", new Block((Body) () -> { - if (objects == Collections.EMPTY_LIST) - { - if (!queryHandle._isValid()) { - QueryWrapper.createQuery(queryHandle); - queryHandle.unwrapBufferCollection().setBuffers(tableHandle.unwrapTempTable().defaultBufferHandle()); - queryHandle.unwrapQuery().prepare(String.format("preselect each %s no-lock", tableHandle.unwrap().name())); - } - - queryHandle.unwrapQuery().open(); - size.assign(queryHandle.unwrapQuery().getNumResults()); - queryHandle.unwrapQuery().close(); - } - else - { - size.assign(objects.size()); - } + if (!queryHandle._isValid()) { + QueryWrapper.createQuery(queryHandle); + queryHandle.unwrapBufferCollection().setBuffers(tableHandle.unwrapTempTable().defaultBufferHandle()); + queryHandle.unwrapQuery().prepare(String.format("preselect each %s", tableHandle.unwrap().name().getValue())); + } + + queryHandle.unwrapQuery().queryOpen(); + size.assign(queryHandle.unwrapQuery().getNumResults()); + queryHandle.unwrapQuery().close(); })); } - - protected Collection> getObjects() - { - return objects; - } } === modified file 'src/com/goldencode/p2j/oo/core/collections/EntrySet.java' --- src/com/goldencode/p2j/oo/core/collections/EntrySet.java 2021-01-13 12:02:59 +0000 +++ src/com/goldencode/p2j/oo/core/collections/EntrySet.java 2021-01-31 10:14:52 +0000 @@ -6,6 +6,8 @@ ** ** -#- -I- --Date-- ---------------------------------------Description---------------------------------------- ** 001 ME 20200514 First version, stubs taken by converting the skeleton using FWD. +** 20201120 Fix remove method return value, removeAll implementation is different +** https://proj.goldencode.com/issues/5010. ** 002 CA 20210113 Renamed Iiterator.next to Iiterator.next_, to follow NameConverter's rules. */ @@ -186,8 +188,10 @@ return function(EntrySet.class, this, "Remove", logical.class, new Block((Body) () -> { Assert.isType(p1, ObjectOps.getLegacyClass(ImapEntry.class)); - - returnNormal(getOwningMap().ref().remove(((ImapEntry) p1.ref()).getKey())); + + object removed = getOwningMap().ref().remove(((ImapEntry) p1.ref()).getKey()); + + returnNormal(!removed.isUnknown()); })); } @@ -202,16 +206,16 @@ return function(EntrySet.class, this, "RemoveAll", logical.class, new Block((Body) () -> { // no check for null on 4GL implementation - //Assert.notNull(p1, new character("Check collection")); - + Iiterator it = p1.ref().iterator().ref(); - + while (it.hasNext().booleanValue()) { + // there seems to be a bug in 4GL, only if entry is found and key equals value it is removed remove(it.next_()); } - // local variable used in 4GL is never updated to true + // 4GL always seems to return false returnNormal(false); })); } === modified file 'src/com/goldencode/p2j/oo/core/collections/LegacyCollection.java' --- src/com/goldencode/p2j/oo/core/collections/LegacyCollection.java 2020-06-15 00:40:59 +0000 +++ src/com/goldencode/p2j/oo/core/collections/LegacyCollection.java 2021-01-31 10:14:52 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 ME 20200519 First version, stubs taken by converting the skeleton using FWD. +** 002 ME 20210128 Implement this using a Java collection, simply override all from AbstratTTCollection. ** */ @@ -66,14 +67,23 @@ import com.goldencode.p2j.util.*; import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; + +import com.goldencode.p2j.oo.core.Assert; import com.goldencode.p2j.oo.core.collections.AbstractTtcollection; import com.goldencode.p2j.oo.lang._BaseObject_; +import com.goldencode.p2j.persist.TemporaryBuffer; -import static com.goldencode.p2j.report.ReportConstants.CVT_LVL_FULL; -import static com.goldencode.p2j.report.ReportConstants.RT_LVL_FULL; +import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.*; import static com.goldencode.p2j.util.InternalEntry.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + /** * Business logic (converted to Java from the 4GL source code * in OpenEdge/Core/Collections/Collection.cls). @@ -83,6 +93,8 @@ public class LegacyCollection extends AbstractTtcollection { + private Collection> objects; + public void __core_collections_LegacyCollection_execute__() { externalProcedure(LegacyCollection.class, LegacyCollection.this, new Block((Body) () -> @@ -98,6 +110,7 @@ internalProcedure(LegacyCollection.class, this, "__core_collections_Collection_constructor__", new Block((Body) () -> { __core_collections_AbstractTtcollection_constructor__(); + objects = new ArrayList>(); })); } @@ -112,11 +125,84 @@ internalProcedure(LegacyCollection.class, this, "__core_collections_Collection_constructor__", new Block((Body) () -> { - __core_collections_AbstractTtcollection_constructor__(); + __core_collections_LegacyCollection_constructor__(); addAll(c); })); } + @LegacySignature(type = Type.GETTER, name = "Size") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + @Override + public integer getSize() + { + return function(this, "Size", integer.class, new Block((Body) () -> { + returnNormal(objects.size()); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Add", parameters = { + @LegacyParameter(name = "p1", type = "OBJECT", qualified = "progress.lang.object", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + @Override + public logical add(final object _p1) + { + object p1 = TypeFactory.initInput(_p1); + + return function(this, "Add", logical.class, new Block((Body) () -> { + returnNormal(p1._isValid() && objects.add(p1)); + })); + } + + @LegacySignature(type = Type.METHOD, name = "AddArray", parameters = { + @LegacyParameter(name = "p1", type = "OBJECT", extent = -1, qualified = "progress.lang.object", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + @Override + public logical addArray(final object[] _p1) + { + object p1[] = TypeFactory.initInput(_p1); + + return function(this, "AddArray", logical.class, new Block((Body) () -> { + if (p1.length > 0) + { + objects.addAll(Arrays.asList(p1)); + } + + returnNormal(true); + })); + } + + @LegacySignature(type = Type.METHOD, name = "AddAll", parameters = { + @LegacyParameter(name = "p1", type = "OBJECT", qualified = "openedge.core.collections.icollection", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + @Override + public logical addAll(final object _p1) + { + object p1 = TypeFactory.initInput(_p1); + + return function(this, "AddAll", logical.class, new Block((Body) () -> { + if (ObjectOps.typeOf(p1, LegacyCollection.class).booleanValue()) + { + objects.addAll(ObjectOps.cast(p1, LegacyCollection.class).ref().objects); + returnNormal(true); + } + else + { + returnNormal(super.addAll(p1)); + } + })); + } + + @LegacySignature(type = Type.METHOD, name = "Clear") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + @Override + public void clear_() + { + internalProcedure(this, "Clear", new Block((Body) () -> + { + objects.clear(); + })); + } + @LegacySignature(type = Type.METHOD, name = "Contains", parameters = { @LegacyParameter(name = "checkObject", type = "OBJECT", qualified = "progress.lang.object", mode = "INPUT") @@ -129,13 +215,181 @@ return function(LegacyCollection.class, this, "Contains", logical.class, new Block((Body) () -> { - if (!checkObject._isValid()) - returnNormal(false); - - returnNormal(super.contains(checkObject)); - })); - } - + returnNormal(_find(checkObject).isValid()); + })); + } + + protected object _find( + final object checkObject) + { + // in 4GL objects are also matched using equals (LegacyEquals) + if (checkObject._isValid()) + { + if (objects.contains(checkObject)) + return checkObject; + + Optional> found = objects.stream() + .filter(o -> checkObject.ref().legacyEquals(o).booleanValue()).findFirst(); + + if (found.isPresent()) + return found.get(); + } + + return checkObject; + } + + @LegacySignature(type = Type.METHOD, name = "ContainsAll", parameters = { + @LegacyParameter(name = "p1", type = "OBJECT", qualified = "openedge.core.collections.icollection", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + @Override + public logical containsAll(final object _p1) + { + object p1 = TypeFactory.initInput(_p1); + + return function(this, "ContainsAll", logical.class, new Block((Body) () -> { + + Assert.notNull(p1, new character("Collection to check")); + + if (ObjectOps.typeOf(p1, LegacyCollection.class).booleanValue()) + { + LegacyCollection other = ObjectOps.cast(p1, LegacyCollection.class).ref(); + + if (other.objects.isEmpty()) + returnNormal(true); + + // this is handled like a set not collection + if (other.objects.size() > objects.size()) + returnNormal(false); + + returnNormal(!other.objects.stream().filter(o -> !_find(o)._isValid()).findFirst().isPresent()); + } + else + { + returnNormal(super.containsAll(p1)); + } + + })); + } + + @LegacySignature(type = Type.METHOD, name = "Iterator", qualified = "openedge.core.collections.iiterator") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + @Override + public object iterator() + { + return function(this, "Iterator", object.class, new Block((Body) () -> { + returnNormal(ObjectOps.newInstance(LegacyIterator.class, "III", new object(this), + new handle(new TransparentWrapper(objects)), "")); + })); + } + + @LegacySignature(type = Type.METHOD, name = "IsEmpty") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + @Override + public logical isEmpty() + { + return function(this, "IsEmpty", logical.class, new Block((Body) () -> { + returnNormal(objects.isEmpty()); + })); + } + + @LegacySignature(type = Type.METHOD, name = "ToTable", parameters = { + @LegacyParameter(name = "p1", type = "HANDLE", mode = "OUTPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @Override + public void toTable(final TableParameter _p1) + { + handle p1 = new handle(); + + internalProcedure(AbstractTtcollection.class, this, "ToTable", new Block((Init) () -> + { + TypeFactory.initOutput(p1); + }, (Body) () -> + { + // TODO: create table from collection + TemporaryBuffer.createDynamicTable(_p1, p1, false, true); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Remove", parameters = { + @LegacyParameter(name = "p1", type = "OBJECT", qualified = "progress.lang.object", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + @Override + public logical remove(final object _p1) + { + object p1 = TypeFactory.initInput(_p1); + + return function(this, "Remove", logical.class, new Block((Body) () -> { + object match = _find(p1); + + returnNormal(match._isValid() && objects.remove(match)); + })); + } + + @LegacySignature(type = Type.METHOD, name = "RemoveAll", parameters = { + @LegacyParameter(name = "p1", type = "OBJECT", qualified = "openedge.core.collections.icollection", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + @Override + public logical removeAll(final object _p1) + { + object p1 = TypeFactory.initInput(_p1); + + return function(this, "RemoveAll", logical.class, new Block((Body) () -> { + if (p1._isValid() && ObjectOps.typeOf(p1, LegacyCollection.class).booleanValue()) + { + LegacyCollection other = ObjectOps.cast(p1, LegacyCollection.class).ref(); + + List matches = other.objects.stream().map(o -> _find(o)).filter(o -> o._isValid()).collect(Collectors.toList()); + + returnNormal(objects.removeAll(matches)); + } + else + { + returnNormal(super.removeAll(p1)); + } + })); + } + + @LegacySignature(type = Type.METHOD, name = "RetainAll", parameters = { + @LegacyParameter(name = "p1", type = "OBJECT", qualified = "openedge.core.collections.icollection", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + @Override + public logical retainAll(final object _p1) + { + object p1 = TypeFactory.initInput(_p1); + + return function(this, "RetainAll", logical.class, new Block((Body) () -> { + if (ObjectOps.typeOf(p1, LegacyCollection.class).booleanValue()) + { + LegacyCollection other = ObjectOps.cast(p1, LegacyCollection.class).ref(); + + List matches = other.objects.stream().map(o -> _find(o)).filter(o -> o._isValid()).collect(Collectors.toList()); + + returnNormal(objects.retainAll(matches)); + } + else + { + returnNormal(super.retainAll(p1)); + } + })); + } + + @LegacySignature(type = Type.METHOD, name = "ToArray", extent = -1, qualified = "progress.lang.object") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + @Override + public object[] toArray() + { + return extentFunction(this, "ToArray", object.class, new Block((Body) () -> { + returnExtentNormal(objects.toArray(new object[objects.size()])); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Resize") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + @Override + protected void resize() { + // NO-OP + } + @LegacySignature(type = Type.METHOD, name = "FindBufferUseObject", parameters = { @LegacyParameter(name = "obj", type = "OBJECT", qualified = "progress.lang.object", mode = "INPUT") @@ -164,13 +418,18 @@ returnNormal(true); if (ObjectOps.typeOf(o, Icollection.class).booleanValue()) { - object other = (object) o; + object other = ObjectOps.cast(o, Icollection.class); - returnNormal(getObjects().size() == other.ref().getSize().intValue() && + returnNormal(objects.size() == other.ref().getSize().intValue() && containsAll(other).booleanValue()); } returnNormal(false); })); } + + protected Collection> getObjects() + { + return objects; + } } === modified file 'src/com/goldencode/p2j/oo/core/collections/LegacyIterator.java' --- src/com/goldencode/p2j/oo/core/collections/LegacyIterator.java 2021-01-13 12:02:59 +0000 +++ src/com/goldencode/p2j/oo/core/collections/LegacyIterator.java 2021-01-31 10:14:52 +0000 @@ -6,7 +6,11 @@ ** ** -#- -I- --Date-- ---------------------------------------Description---------------------------------------- ** 001 ME 20200514 First version, stubs taken by converting the skeleton using FWD. -** 002 CA 20210113 Renamed Iiterator.next to Iiterator.next_, to follow NameConverter's rules. +** 002 ME 20201016 Change it to work with the collection image at the time of instantiation. +** No protection against collection modification initial image is needed, +** accommodate other 4GL oddities. +** +** 003 CA 20210113 Renamed Iiterator.next to Iiterator.next_, to follow NameConverter's rules. */ /* @@ -77,11 +81,10 @@ import static com.goldencode.p2j.util.BlockManager.*; import static com.goldencode.p2j.util.InternalEntry.Type; +import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; -import org.apache.commons.lang.StringUtils; - /** * Business logic (converted to Java from the 4GL source code * in OpenEdge/Core/Collections/Iterator.cls). @@ -102,7 +105,11 @@ @LegacySignature(type = Type.PROPERTY, name = "ObjectFieldHandle") private handle objectFieldHandle = TypeFactory.handle(); + private Collection objectsCollection; + private boolean emptyCollection; + private Iterator> iterator; + private object next; public void __core_collections_LegacyIterator_execute__() { @@ -266,33 +273,39 @@ ownerCollection.assign(oCol); // default 4GL temp-table implementation - if (phTT.isType(LegacyResource.TEMP_TABLE)) + if (phTT.isType(LegacyResource.TEMP_TABLE) || phTT.isType(LegacyResource.BUFFER)) { RecordBuffer.create(bufferHandle, phTT); + + objectFieldHandle.assign(bufferHandle.unwrapBuffer().bufferField(valField)); QueryWrapper.createQuery(queryHandle); queryHandle.unwrapBufferCollection().setBuffers(bufferHandle); StringBuffer qryString = new StringBuffer(); - if (!StringUtils.isBlank(whereString.getValue())) + if (!TextOps.isEmpty(whereString.getValue())) qryString.append(" where " + whereString.getValue()); - if (!StringUtils.isBlank(sortField.getValue())) + if (!TextOps.isEmpty(sortField.getValue())) qryString.append(" by " + sortField.getValue()); else queryHandle.unwrapQuery().changeForwardOnly(true); - queryHandle.unwrapQuery() - .prepare(String.format("preselect each %s &s no-lock", - bufferHandle.unwrap().name(), qryString.toString())); + .prepare(String.format("preselect each %s %s no-lock", + bufferHandle.unwrap().name().getValue(), qryString.toString())); - queryHandle.unwrapQuery().open(); + queryHandle.unwrapQuery().queryOpen(); iterator = null; } else { Object resource = phTT.get(); - if (resource instanceof Collection) - iterator = ((Collection) resource).iterator(); + if (resource instanceof Collection) { + // keep a reference to the actual objects collections + objectsCollection = (Collection) resource; + emptyCollection = objectsCollection.isEmpty(); + // make a copy so the iterator always sees the elements present when created + iterator = new ArrayList(objectsCollection).iterator(); + } } })); } @@ -303,8 +316,11 @@ { return function(LegacyIterator.class, this, "HasNext", logical.class, new Block((Body) () -> { - if (iterator != null) - returnNormal(iterator.hasNext()); + if (iterator != null) + { + // 4GL BUG, if collection (temp-table) was empty hasNext returns unknown + returnNormal(emptyCollection ? new logical() : new logical(iterator.hasNext())); + } else { P2JQuery qry = queryHandle.unwrapQuery(); @@ -334,8 +350,24 @@ { return function(LegacyIterator.class, this, "Next", object.class, new Block((Body) () -> { - if (iterator != null) - returnNormal(iterator.next()); + if (iterator != null) + { + while (iterator.hasNext()) { + next = iterator.next(); + + // check if object still in original collection, if removed skip + if (objectsCollection.contains(next)) + { + returnNormal(next); + } + else + { + next = null; + } + } + + returnNormal(new object()); + } else { queryHandle.unwrapQuery().next(); @@ -359,15 +391,20 @@ { if (iterator != null) { - try + if (next == null) + { + returnNormal(false); + } + else { iterator.remove(); + // remove the item from parent collection, iterator is working on a copy + if (ownerCollection._isValid()) + ownerCollection.ref().remove(next); + next = null; + returnNormal(true); } - catch (Exception e) - { - returnNormal(false); - } } else { === modified file 'src/com/goldencode/p2j/oo/core/collections/LegacyMap.java' --- src/com/goldencode/p2j/oo/core/collections/LegacyMap.java 2021-01-13 15:36:44 +0000 +++ src/com/goldencode/p2j/oo/core/collections/LegacyMap.java 2021-01-31 10:14:52 +0000 @@ -89,6 +89,8 @@ public class LegacyMap extends BaseObject implements com.goldencode.p2j.oo.core.collections.Imap { private HashMap map = new LinkedHashMap(); + // 4GL BUG, size not reset on clear + private int size = 0; public void __core_collections_LegacyMap_execute__() { @@ -106,7 +108,7 @@ { return function(LegacyMap.class, this, "Size", integer.class, new Block((Body) () -> { - returnNormal(new integer(map.size())); + returnNormal(new integer(size)); })); } @@ -160,7 +162,7 @@ public logical legacyEquals( final object other) { - if (other.ref() instanceof Imap) + if (!other.isUnknown() && other.ref() instanceof Imap) { Imap omap = (Imap) other.ref(); @@ -282,7 +284,18 @@ return function(LegacyMap.class, this, "ContainsValue", logical.class, new Block((Body) () -> { - returnNormal(new logical(map.containsValue(poValue))); + if (!poValue.isUnknown()) { + // walk through all values instead of containsValue + // 4GL BUG: because if one of the values in the list is invalid error is thrown + for (object value : map.values()) + { + if (value.ref().legacyEquals(poValue).booleanValue()) + returnNormal(new logical(true)); + } + } + + returnNormal(new logical(false)); + })); } @@ -325,6 +338,9 @@ object obj = map.put(poKey, poValue); + if (obj == null) + size++; + returnNormal(obj != null ? obj : new object()); })); } @@ -364,6 +380,9 @@ object obj = map.remove(poKey); + if (obj != null) + size--; + returnNormal(obj != null ? obj : new object()); })); } === modified file 'src/com/goldencode/p2j/oo/core/collections/LegacyMapEntry.java' --- src/com/goldencode/p2j/oo/core/collections/LegacyMapEntry.java 2020-05-18 08:10:56 +0000 +++ src/com/goldencode/p2j/oo/core/collections/LegacyMapEntry.java 2020-10-14 12:51:31 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 ME 20200514 First version, stubs taken by converting the skeleton using FWD. +** 20201014 Use different error number for chained reference in equals. ** */ @@ -198,9 +199,14 @@ if (ObjectOps.typeOf(p1, ImapEntry.class).booleanValue()) { ImapEntry other = (ImapEntry) p1.ref(); + object val = getValue(); + // chained reference, different error number + if (key.isUnknown() || val.isUnknown()) + ErrorManager.recordOrThrowError(10068); + returnNormal(key.ref().legacyEquals(other.getKey()).booleanValue() && - getValue().ref().legacyEquals(other.getValue()).booleanValue()); + val.ref().legacyEquals(other.getValue()).booleanValue()); } returnNormal(false); === modified file 'src/com/goldencode/p2j/oo/core/collections/LegacySet.java' --- src/com/goldencode/p2j/oo/core/collections/LegacySet.java 2021-01-13 12:02:59 +0000 +++ src/com/goldencode/p2j/oo/core/collections/LegacySet.java 2021-01-31 10:14:52 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- ---------------------------------------Description---------------------------------------- ** 001 ME 20200514 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20210113 Renamed Iiterator.next to Iiterator.next_, to follow NameConverter's rules. +** 003 ME 20210128 Implement it by extending Collection instead of AbstractTTCollection. */ /* @@ -67,7 +68,6 @@ import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; import com.goldencode.p2j.oo.core.Assert; -import com.goldencode.p2j.oo.core.collections.AbstractTtcollection; import com.goldencode.p2j.oo.core.collections.Iset; import com.goldencode.p2j.oo.lang._BaseObject_; @@ -82,7 +82,7 @@ */ @LegacyResource(resource = "OpenEdge.Core.Collections.Set") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) -public class LegacySet extends AbstractTtcollection implements Iset +public class LegacySet extends LegacyCollection implements Iset { public void __core_collections_LegacySet_execute__() { @@ -99,7 +99,7 @@ internalProcedure(LegacySet.class, this, "__core_collections_LegacySet_constructor__", new Block((Body) () -> { - __core_collections_AbstractTtcollection_constructor__(); + __core_collections_LegacyCollection_constructor__(); })); } @@ -113,37 +113,10 @@ internalProcedure(LegacySet.class, this, "__core_collections_LegacySet_constructor__", new Block((Body) () -> { - __core_collections_AbstractTtcollection_constructor__(); - addAll(p1); + __core_collections_LegacyCollection_constructor__(p1); })); } - @LegacySignature(type = Type.METHOD, name = "Contains", parameters = { - @LegacyParameter(name = "p1", type = "OBJECT", qualified = "progress.lang.object", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) - @Override - public logical contains(final object _p1) - { - object p1 = TypeFactory.initInput(_p1); - - return function(LegacySet.class, this, "Contains", logical.class, new Block((Body) () -> - { - if (!p1._isValid()) - returnNormal(false); - - returnNormal(super.contains(p1)); - })); - } - - @LegacySignature(type = Type.METHOD, name = "FindBufferUseObject", parameters = { - @LegacyParameter(name = "p1", type = "OBJECT", qualified = "progress.lang.object", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) - @Override - protected void findBufferUseObject(final object _p1) - { - // no-op since this is using a java collection not 4gl temp-table - } - @LegacySignature(type = Type.METHOD, name = "Add", parameters = { @LegacyParameter(name = "p1", type = "OBJECT", qualified = "progress.lang.object", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) @@ -156,7 +129,7 @@ { Assert.notNull(p1, new character("Object to add")); - if (getObjects().contains(p1)) + if (_find(p1)._isValid()) returnNormal(false); returnNormal(getObjects().add(p1)); @@ -173,15 +146,29 @@ return function(LegacySet.class, this, "AddAll", logical.class, new Block((Body) () -> { - - Iiterator it = p1.ref().iterator().ref(); boolean ok = false; - while(it.hasNext().booleanValue()) { - ok = add(it.next_()).booleanValue() || ok; + if (ObjectOps.typeOf(p1, LegacyCollection.class).booleanValue()) + { + LegacyCollection other = ObjectOps.cast(p1, LegacyCollection.class).ref(); + + for (object o : other.getObjects()) + { + ok = (!_find(o)._isValid() && getObjects().add(o)) || ok; + } + } + else + { + Iiterator it = p1.ref().iterator().ref(); + + while(it.hasNext().booleanValue()) { + ok = add(it.next_()).booleanValue() || ok; + } + } returnNormal(ok); + })); } @@ -200,7 +187,7 @@ returnNormal(true); if (ObjectOps.typeOf(p1, Iset.class).booleanValue()) { - object other = (object) p1; + object other = ObjectOps.cast(p1, Iset.class); returnNormal(getObjects().size() == other.ref().getSize().intValue() && containsAll(other).booleanValue()); @@ -210,45 +197,4 @@ })); } - @LegacySignature(type = Type.METHOD, name = "RemoveAll", parameters = { - @LegacyParameter(name = "p1", type = "OBJECT", qualified = "openedge.core.collections.icollection", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) - @Override - public logical removeAll(final object _p1) - { - object p1 = TypeFactory.initInput(_p1); - - return function(LegacySet.class, this, "RemoveAll", logical.class, new Block((Body) () -> - { - boolean result = false; - Iiterator it = p1.ref().iterator().ref(); - - while (it.hasNext().booleanValue()) - { - result = getObjects().remove(it.next_()) || result; - } - - returnNormal(result); - })); - } - - - @Override - public integer getSize() - { - // use java collection instead of local variable - return new integer(getObjects().size()); - } - - @Override - protected void resize() - { - // no-op - } - - @Override - public logical remove(object _p1) - { - return new logical(_p1._isValid() && getObjects().remove(_p1)); - } } === added file 'src/com/goldencode/p2j/oo/core/collections/StackOverflowError.java' --- src/com/goldencode/p2j/oo/core/collections/StackOverflowError.java 1970-01-01 00:00:00 +0000 +++ src/com/goldencode/p2j/oo/core/collections/StackOverflowError.java 2020-12-17 07:18:22 +0000 @@ -0,0 +1,113 @@ +/* + ** Module : StackOverflowError.java + ** Abstract : Implementation of the OpenEdge.Core.Collections.StackOverflowError class. + ** + ** Copyright (c) 2018-2020, Golden Code Development Corporation. + ** + ** -#- -I- --Date-- -------------------------------Description-------------------------------- + ** 001 ME 20201216 First version. + */ + +/* + ** This program is free software: you can redistribute it and/or modify + ** it under the terms of the GNU Affero General Public License as + ** published by the Free Software Foundation, either version 3 of the + ** License, or (at your option) any later version. + ** + ** This program is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU Affero General Public License for more details. + ** + ** You may find a copy of the GNU Affero GPL version 3 at the following + ** location: https://www.gnu.org/licenses/agpl-3.0.en.html + ** + ** Additional terms under GNU Affero GPL version 3 section 7: + ** + ** Under Section 7 of the GNU Affero GPL version 3, the following additional + ** terms apply to the works covered under the License. These additional terms + ** are non-permissive additional terms allowed under Section 7 of the GNU + ** Affero GPL version 3 and may not be removed by you. + ** + ** 0. Attribution Requirement. + ** + ** You must preserve all legal notices or author attributions in the covered + ** work or Appropriate Legal Notices displayed by works containing the covered + ** work. You may not remove from the covered work any author or developer + ** credit already included within the covered work. + ** + ** 1. No License To Use Trademarks. + ** + ** This license does not grant any license or rights to use the trademarks + ** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks + ** of Golden Code Development Corporation. You are not authorized to use the + ** name Golden Code, FWD, or the names of any author or contributor, for + ** publicity purposes without written authorization. + ** + ** 2. No Misrepresentation of Affiliation. + ** + ** You may not represent yourself as Golden Code Development Corporation or FWD. + ** + ** You may not represent yourself for publicity purposes as associated with + ** Golden Code Development Corporation, FWD, or any author or contributor to + ** the covered work, without written authorization. + ** + ** 3. No Misrepresentation of Source or Origin. + ** + ** You may not represent the covered work as solely your work. All modified + ** versions of the covered work must be marked in a reasonable way to make it + ** clear that the modified work is not originating from Golden Code Development + ** Corporation or FWD. All modified versions must contain the notices of + ** attribution required in this license. + */ +package com.goldencode.p2j.oo.core.collections; + +import com.goldencode.p2j.util.*; +import com.goldencode.p2j.util.BlockManager.Action; +import com.goldencode.p2j.util.BlockManager.Condition; + +import static com.goldencode.p2j.report.ReportConstants.CVT_LVL_FULL; +import static com.goldencode.p2j.report.ReportConstants.RT_LVL_FULL; +import static com.goldencode.p2j.util.BlockManager.*; +import static com.goldencode.p2j.util.InternalEntry.Type; + +import com.goldencode.p2j.oo.core.system.ApplicationError; + +/** + * Business logic (converted to Java from the 4GL source code + * in abl/skeleton/oo4gl/OpenEdge/Core/Collections/StackOverflowError.cls). + */ +@LegacyResource(resource = "OpenEdge.Core.Collections.StackOverflowError") +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) +public class StackOverflowError extends ApplicationError +{ + public void __core_collections_StackOverflowError_execute__() + { + externalProcedure(StackOverflowError.class, StackOverflowError.this, new Block((Body) () -> { + onBlockLevel(Condition.ERROR, Action.THROW); + })); + } + + @LegacySignature(type = Type.CONSTRUCTOR) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public static void __core_collections_StackOverflowError_constructor__static__() + { + externalProcedure(StackOverflowError.class, new Block((Body) () -> { + onBlockLevel(Condition.ERROR, Action.THROW); + ApplicationError.addError(new object<>(ObjectOps.getClassInstance(StackOverflowError.class)), + new character("Stack Overflow Error"), + new longchar("Stack overflow error")); + })); + } + + @LegacySignature(type = Type.CONSTRUCTOR) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void __core_collections_StackOverflowError_constructor__() + { + internalProcedure(StackOverflowError.class, this, "__core_collections_StackOverflowError_constructor__", + new Block((Body) () -> { + __core_system_ApplicationError_constructor__(); + })); + } + +} === added file 'src/com/goldencode/p2j/oo/core/collections/StackUnderflowError.java' --- src/com/goldencode/p2j/oo/core/collections/StackUnderflowError.java 1970-01-01 00:00:00 +0000 +++ src/com/goldencode/p2j/oo/core/collections/StackUnderflowError.java 2020-12-17 07:18:22 +0000 @@ -0,0 +1,113 @@ +/* + ** Module : StackUnderflowError.java + ** Abstract : Implementation of the OpenEdge.Core.Collections.StackUnderflowError class. + ** + ** Copyright (c) 2018-2020, Golden Code Development Corporation. + ** + ** -#- -I- --Date-- -------------------------------Description-------------------------------- + ** 001 ME 20201216 First version. + */ + +/* + ** This program is free software: you can redistribute it and/or modify + ** it under the terms of the GNU Affero General Public License as + ** published by the Free Software Foundation, either version 3 of the + ** License, or (at your option) any later version. + ** + ** This program is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU Affero General Public License for more details. + ** + ** You may find a copy of the GNU Affero GPL version 3 at the following + ** location: https://www.gnu.org/licenses/agpl-3.0.en.html + ** + ** Additional terms under GNU Affero GPL version 3 section 7: + ** + ** Under Section 7 of the GNU Affero GPL version 3, the following additional + ** terms apply to the works covered under the License. These additional terms + ** are non-permissive additional terms allowed under Section 7 of the GNU + ** Affero GPL version 3 and may not be removed by you. + ** + ** 0. Attribution Requirement. + ** + ** You must preserve all legal notices or author attributions in the covered + ** work or Appropriate Legal Notices displayed by works containing the covered + ** work. You may not remove from the covered work any author or developer + ** credit already included within the covered work. + ** + ** 1. No License To Use Trademarks. + ** + ** This license does not grant any license or rights to use the trademarks + ** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks + ** of Golden Code Development Corporation. You are not authorized to use the + ** name Golden Code, FWD, or the names of any author or contributor, for + ** publicity purposes without written authorization. + ** + ** 2. No Misrepresentation of Affiliation. + ** + ** You may not represent yourself as Golden Code Development Corporation or FWD. + ** + ** You may not represent yourself for publicity purposes as associated with + ** Golden Code Development Corporation, FWD, or any author or contributor to + ** the covered work, without written authorization. + ** + ** 3. No Misrepresentation of Source or Origin. + ** + ** You may not represent the covered work as solely your work. All modified + ** versions of the covered work must be marked in a reasonable way to make it + ** clear that the modified work is not originating from Golden Code Development + ** Corporation or FWD. All modified versions must contain the notices of + ** attribution required in this license. + */ +package com.goldencode.p2j.oo.core.collections; + +import com.goldencode.p2j.util.*; +import com.goldencode.p2j.util.BlockManager.Action; +import com.goldencode.p2j.util.BlockManager.Condition; + +import static com.goldencode.p2j.report.ReportConstants.CVT_LVL_FULL; +import static com.goldencode.p2j.report.ReportConstants.RT_LVL_FULL; +import static com.goldencode.p2j.util.BlockManager.*; +import static com.goldencode.p2j.util.InternalEntry.Type; + +import com.goldencode.p2j.oo.core.system.ApplicationError; + +/** + * Business logic (converted to Java from the 4GL source code + * in abl/skeleton/oo4gl/OpenEdge/Core/Collections/StackUnderflowError.cls). + */ +@LegacyResource(resource = "OpenEdge.Core.Collections.StackUnderflowError") +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) +public class StackUnderflowError extends ApplicationError +{ + public void __core_collections_StackUnderflowError_execute__() + { + externalProcedure(StackUnderflowError.class, StackUnderflowError.this, new Block((Body) () -> { + onBlockLevel(Condition.ERROR, Action.THROW); + })); + } + + @LegacySignature(type = Type.CONSTRUCTOR) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public static void __core_collections_StackUnderflowError_constructor__static__() + { + externalProcedure(StackUnderflowError.class, new Block((Body) () -> { + onBlockLevel(Condition.ERROR, Action.THROW); + ApplicationError.addError(new object<>(ObjectOps.getClassInstance(StackUnderflowError.class)), + new character("Stack Underflow Error"), + new longchar("Stack underflow error")); + })); + } + + @LegacySignature(type = Type.CONSTRUCTOR) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void __core_collections_StackUnderflowError_constructor__() + { + internalProcedure(StackUnderflowError.class, this, "__core_collections_StackUnderflowError_constructor__", + new Block((Body) () -> { + __core_system_ApplicationError_constructor__(); + })); + } + +} === modified file 'src/com/goldencode/p2j/oo/core/system/ApplicationError.java' --- src/com/goldencode/p2j/oo/core/system/ApplicationError.java 2020-05-18 08:07:57 +0000 +++ src/com/goldencode/p2j/oo/core/system/ApplicationError.java 2020-12-14 10:26:24 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 ME 20200402 First version. + ** 20201214 Fix class map, set severity and override toString, clone. */ /* @@ -75,6 +76,7 @@ import java.util.Map; import com.goldencode.p2j.oo.lang.LegacyClass; +import com.goldencode.p2j.oo.lang._BaseObject_; import com.goldencode.p2j.security.ContextLocal; /** @@ -127,7 +129,7 @@ internalProcedure(ApplicationError.class, "AddError", new Block((Body) () -> { if (!_poType.isUnknown()) { - Class cls = _poType.ref().getClass(); + Class cls = _poType.ref().getType(); String pcShortMessage = _pcShortMessage.isUnknown() ? "" : _pcShortMessage.getValue(); String pcMessage = _pcMessage.isUnknown() ? "" : _pcMessage.getValue(); @@ -155,6 +157,7 @@ internalProcedure(ApplicationError.class, this, "__core_system_ApplicationError_constructor__", new Block((Body) () -> { __lang_AppError_constructor__(); + setSeverity(new integer(ErrorSeverityEnum.default_.ref()._getValue())); })); } @@ -166,7 +169,7 @@ { internalProcedure(ApplicationError.class, this, "__core_system_ApplicationError_constructor__", new Block((Body) () -> { - __lang_AppError_constructor__(); + __core_system_ApplicationError_constructor__(); this.innerError.assign(_p1); })); } @@ -211,6 +214,36 @@ returnNormal(new longchar("")); })); } + + + @LegacySignature(type = Type.METHOD, name = "ToString") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + @Override + public character toLegacyString() + { + return getShortMessage(); + } + + @LegacySignature(type = Type.METHOD, name = "Clone") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + @Override + public object clone() + { + object err = TypeFactory.object(ApplicationError.class); + + err.assign(ObjectOps.newInstance(getClass(), "I", innerError)); + err.ref().setSeverity(severity); + err.ref().setReturnValue(getReturnValue()); + + for (int i = 0; i < getNumMessages().intValue(); i++) + { + integer idx = new integer(i + 1); + // message number seems to be ignored + err.ref().addMessage(getMessage(idx), idx); + } + + return err; + } protected String[] getErrorDefinition() { === modified file 'src/com/goldencode/p2j/oo/core/util/ConfigBuilder.java' --- src/com/goldencode/p2j/oo/core/util/ConfigBuilder.java 2020-06-15 00:40:59 +0000 +++ src/com/goldencode/p2j/oo/core/util/ConfigBuilder.java 2020-12-07 11:34:04 +0000 @@ -8,6 +8,9 @@ ** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD. ** 002 IAS 20190923 Implementation of the business logic ** 003 CA 20191024 Added method support levels and updated the class support level. +** 004 ME 20201202 Options map is case insensitive in 4GL. +** 20201207 Use character as map key since unknown keys are allowed in 4GL. +** Add new methods as of OE12.2. */ /* @@ -67,6 +70,7 @@ import static com.goldencode.p2j.util.BlockManager.*; import static com.goldencode.p2j.report.ReportConstants.*; +import static com.goldencode.p2j.util.ErrorManager.*; import java.util.*; @@ -96,7 +100,7 @@ @Override public decimal newInstance() { - return TypeFactory.decimal(); + return new decimal(); } }); put(object.class, new OptionTypeHelper>("object") @@ -113,7 +117,7 @@ @Override public character newInstance() { - return TypeFactory.character(); + return new character(); } }); put(logical.class, new OptionTypeHelper("logical") @@ -121,7 +125,7 @@ @Override public logical newInstance() { - return TypeFactory.logical(); + return new logical(); } }); put(datetimetz.class, new OptionTypeHelper("datetime") @@ -129,14 +133,14 @@ @Override public datetimetz newInstance() { - return TypeFactory.datetimetz(); + return new datetimetz(); } }); }} ); /** Options by name map. */ - protected final Map options = new LinkedHashMap<>(); + protected final Map options = new HashMap(); /** * Execute method. @@ -187,7 +191,7 @@ Assert.notNullOrEmpty(key, new character("Config name")); object arr = TypeFactory.object(JsonArray.class); - arr.assign(hasOption(key).booleanValue() ? + arr.assign(!hasOption(key).booleanValue() ? ObjectOps.newInstance(JsonArray.class) : ObjectOps.cast(getOption(key, object.class), JsonArray.class) ); @@ -220,6 +224,7 @@ { @LegacyParameter(name = "p1", type = "CHARACTER", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public datetimetz getOptionDateTimeValue(final character _p1) { character p1 = TypeFactory.initInput(_p1); @@ -402,10 +407,19 @@ { Assert.notNullOrEmpty(key, new character("Config name")); returnNormal( - new logical(options.containsKey(key.getValue())) + new logical(options.containsKey(key)) ); })); } + + /** + * Check if options map (characters) contains the string key. + * @param key the key name + * @return + */ + protected boolean _hasOption (String key) { + return options.containsKey(new character(key)); + } /** * Removes an option @@ -425,10 +439,7 @@ return function(this, "RemoveOption", logical.class, new Block((Body) () -> { - Assert.notNullOrEmpty(key, new character("Config name")); - returnNormal( - new logical(options.remove(key.getValue()) != null) - ); + returnNormal(new logical(options.remove(key) != null)); })); } @@ -458,6 +469,42 @@ } /** + * Stores a character value as an option. + * + * @param _p1 option name. + * @param _p2 option value, + * + * @return true if the named configuration was replaced. + */ + @LegacySignature(type = Type.METHOD, name = "SetOption", parameters = { + @LegacyParameter(name = "p1", type = "CHARACTER", mode = "INPUT"), + @LegacyParameter(name = "p2", type = "CHARACTER", extent = -1, mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public logical setOption(final character _p1, final character[] _p2) + { + character p1 = TypeFactory.initInput(_p1); + character p2[] = TypeFactory.initInput(_p2); + + return function(this, "SetOption", logical.class, + new Block((Body) () -> { + object json = TypeFactory.object(JsonArray.class); + + if (p2.length > 0) + { + // work around issue on ctor with extent parameter + json.assign(ObjectOps.newInstance(JsonArray.class)); + + for (character chr : p2) + { + json.ref().add(chr); + } + } + + returnNormal(setOption(p1, json)); + })); + } + + /** * Stores a datetime-tz value as an option. * * @param _p1 option name. @@ -558,6 +605,31 @@ } /** + * Stores an object value as an option. + * + * @param _p1 option name. + * @param _p2 option value, + * + * @return true if the named configuration was replaced. + */ + @LegacySignature(type = Type.METHOD, name = "SetOption", parameters = { + @LegacyParameter(name = "p1", type = "OBJECT", qualified = "progress.lang.class", mode = "INPUT"), + @LegacyParameter(name = "p2", type = "OBJECT", qualified = "progress.lang.object", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public logical setOption(final object _p1, + final object _p2) + { + object p1 = TypeFactory.initInput(_p1); + object p2 = TypeFactory.initInput(_p2); + + return function(this, "SetOption", logical.class, new Block((Body) () -> { + Assert.notNull(p1, new character("Config name")); + + returnNormal(setOption(p1.ref().getTypeName(), p2)); + })); + } + + /** * Stores a value as an option. * * @param key option name. @@ -568,10 +640,12 @@ */ private logical setOption(character key, T val, Class cls) { - Assert.notNullOrEmpty(key, new character("Config name")); + // in 4GL the error status is reset, probably some find with no-error + silent(() -> {}); + OptionTypeHelper helper = (OptionTypeHelper) TYPES.get(cls); return new logical( - options.put(key.getValue(), new OptionValueHolder(helper.type, val)) != null + options.put(key, new OptionValueHolder(helper.type, val)) != null ); } @@ -585,9 +659,11 @@ */ private T getOption(character key, Class cls) { - Assert.notNullOrEmpty(key, new character("Config name")); + // in 4GL the error status is reset, probably some find with no-error + silent(() -> {}); + OptionTypeHelper helper = (OptionTypeHelper) TYPES.get(cls); - OptionValueHolder val = options.get(key.getValue()); + OptionValueHolder val = options.get(key); if (val == null) { return helper.newInstance(); === modified file 'src/com/goldencode/p2j/oo/io/FileInputStream.java' --- src/com/goldencode/p2j/oo/io/FileInputStream.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/io/FileInputStream.java 2021-01-30 11:14:42 +0000 @@ -7,6 +7,8 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. ** 002 MP 20200703 Complete code with methods like legacy class +** 003 MP 20210112 improve constructor behavior and add file name in loop +** 004 ME 20210128 Fix ctor/execute names. */ /* @@ -89,7 +91,7 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) private character fileName = TypeFactory.character(); - public void __progress_io_FileInputStream_execute__() + public void __io_FileInputStream_execute__() { externalProcedure(FileInputStream.class, FileInputStream.this, new Block((Body) () -> { @@ -104,13 +106,14 @@ @LegacyParameter(name = "filename", type = "CHARACTER", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void __progress_io_FileInputStream_constructor__(final character _filename) + public void __io_FileInputStream_constructor__(final character _filename) { character filename = TypeFactory.initInput(_filename); - internalProcedure(FileInputStream.class, this, "__progress_io_FileInputStream_constructor__", new Block((Body) () -> + internalProcedure(FileInputStream.class, this, "__io_FileInputStream_constructor__", new Block((Body) () -> { - __progress_io_InputStream_constructor__(); + __io_InputStream_constructor__(); + this.fileName.assign(filename); })); } === modified file 'src/com/goldencode/p2j/oo/io/InputStream.java' --- src/com/goldencode/p2j/oo/io/InputStream.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/io/InputStream.java 2021-01-15 11:17:07 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. ** 002 MP 20200703 Complete code with methods like legacy class +** 003 ME 20201209 Fully implement non-abstract methods. */ /* @@ -76,22 +77,23 @@ import static com.goldencode.p2j.util.BlockManager.internalProcedure; import static com.goldencode.p2j.util.BlockManager.onBlockLevel; import static com.goldencode.p2j.util.BlockManager.returnNormal; +import static com.goldencode.p2j.util.BlockManager.undoThrow; /** * Business logic (converted to Java from the 4GL source code * in Progress/IO/InputStream.cls). */ @LegacyResource(resource = "Progress.IO.InputStream") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public abstract class InputStream extends BaseObject { - @LegacySignature(type = Type.PROPERTY, name = "Close") - private logical close = UndoableFactory.logical(); + @LegacySignature(type = Type.PROPERTY, name = "Closed") + private final logical closed = TypeFactory.logical(false); - public void __progress_io_InputStream_execute__() + public void __io_InputStream_execute__() { - externalProcedure(InputStream.class, InputStream.this, new Block((Body) () -> + externalProcedure(this, new Block((Body) () -> { onBlockLevel(Condition.ERROR, Action.THROW); { @@ -100,32 +102,32 @@ } @LegacySignature(type = Type.CONSTRUCTOR) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void __progress_io_InputStream_constructor__() + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void __io_InputStream_constructor__() { - internalProcedure(InputStream.class, this, "__progress_io_InputStream_constructor__", new Block((Body) () -> + internalProcedure(this, "__io_InputStream_constructor__", new Block((Body) () -> { __lang_BaseObject_constructor__(); })); } - @LegacySignature(type = Type.GETTER, name = "Close") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public logical getClose() + @LegacySignature(type = Type.GETTER, name = "Closed") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public logical getClosed() { - return function(InputStream.class, this, "Close", logical.class, new Block((Body) () -> + return function(this, "Closed", logical.class, new Block((Body) () -> { - returnNormal(close); + returnNormal(closed); })); } @LegacySignature(type = Type.METHOD, name = "Close") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void close() { - internalProcedure(InputStream.class, this, "Close", new Block((Body) () -> + internalProcedure(this, "Close", new Block((Body) () -> { - UnimplementedFeature.missing("InputStream:Close METHOD"); + this.closed.assign(true); })); } @@ -133,54 +135,90 @@ { @LegacyParameter(name = "target", type = "MEMPTR", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public int64 read(final memptr _target) { memptr target = TypeFactory.initInput(_target); - return function(InputStream.class, this, "Read", int64.class, new Block((Body) () -> + return function(this, "Read", int64.class, new Block((Body) () -> { - UnimplementedFeature.missing("InputStream:Read METHOD"); + if (closed.booleanValue()) + { + ErrorManager.recordOrThrowError(18196, "Cannot invoke method 'Read' after stream has been closed", false); + } + + if (target.isUninitialized()) + { + ErrorManager.recordOrThrowError(19066, "Invalid parameter: An initialized MEMPTR must be provided for the Read method or constructor.", false); + } + + returnNormal(read(target, new int64(1), target.length())); })); } + @LegacySignature(type = Type.METHOD, name = "Read", parameters = { + @LegacyParameter(name = "target", type = "HANDLE", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public int64 read(final handle target) + { + return function(this, "Read", int64.class, new Block((Body) () -> { + ErrorManager.recordOrThrowError(18192, + "Cannot invoke Read method in 'Progress.IO.InputStream' because it is not implemented", + false); + })); + } + @LegacySignature(type = Type.METHOD, name = "Read", parameters = { @LegacyParameter(name = "target", type = "MEMPTR", mode = "INPUT"), @LegacyParameter(name = "offset", type = "INT64", mode = "INPUT"), @LegacyParameter(name = "length", type = "INT64", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public abstract int64 read(final memptr _target, final int64 _offset, final int64 _length); + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public abstract int64 read(final memptr target, final int64 offset, final int64 length); @LegacySignature(type = Type.METHOD, name = "Read", parameters = { @LegacyParameter(name = "delimiter", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "target", type = "CHARACTER", mode = "OUTPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public abstract int64 read(final character _delimiter, final character target); + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public abstract int64 read(final character delimiter, final character target); @LegacySignature(type = Type.METHOD, name = "Read", parameters = { @LegacyParameter(name = "delimiter", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "target", type = "LONGCHAR", mode = "OUTPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public abstract int64 read(final character _delimiter, final longchar target); + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public abstract int64 read(final character delimiter, final longchar target); @LegacySignature(type = Type.METHOD, name = "SkipBytes", parameters = { @LegacyParameter(name = "n", type = "INT64", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public int64 skipBytes(final int64 _n) { int64 n = TypeFactory.initInput(_n); + memptr mPtr = TypeFactory.memptr(); - return function(InputStream.class, this, "SkipBytes", int64.class, new Block((Body) () -> + return function(this, "SkipBytes", int64.class, new Block((Body) () -> { - UnimplementedFeature.missing("InputStream:SkipBytes METHOD"); + if (closed.booleanValue()) + { + ErrorManager.recordOrThrowError(18196, "Cannot invoke method 'SkipBytes' after stream has been closed", false); + } + + // consume the number of bytes from input + mPtr.setLength(n); + + // offset is zero for skip, maybe a hint for read to discard that data + n.assign(read(mPtr, new int64(0), n)); + + returnNormal(n); + }, (Fini) () -> { + mPtr.setLength(0); })); } === modified file 'src/com/goldencode/p2j/oo/io/OutputStream.java' --- src/com/goldencode/p2j/oo/io/OutputStream.java 2019-10-24 23:19:26 +0000 +++ src/com/goldencode/p2j/oo/io/OutputStream.java 2021-01-15 11:17:07 +0000 @@ -8,6 +8,8 @@ ** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20190720 Added LegacyResource annotation. ** 003 CA 20191024 Added method support levels and updated the class support level. +** 004 ME 20201208 Add missing implementation, update support level. +** 005 ME 20201209 Fully implement non-abstract methods. */ /* @@ -66,6 +68,8 @@ package com.goldencode.p2j.oo.io; import com.goldencode.p2j.util.*; +import com.goldencode.p2j.util.BlockManager.Action; +import com.goldencode.p2j.util.BlockManager.Condition; import com.goldencode.p2j.oo.lang.*; import static com.goldencode.p2j.util.BlockManager.*; @@ -77,23 +81,23 @@ * in Progress/IO/OutputStream.cls). */ @LegacyResource(resource = "Progress.IO.OutputStream") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public abstract class OutputStream extends BaseObject { - private logical closed = UndoableFactory.logical(); + @LegacySignature(type = Type.PROPERTY, name = "Closed") + private final logical closed = TypeFactory.logical(false); public void __io_OutputStream_execute__() { externalProcedure(OutputStream.this, new Block((Body) () -> { - { - } + onBlockLevel(Condition.ERROR, Action.THROW); })); } @LegacySignature(type = Type.CONSTRUCTOR) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __io_OutputStream_constructor__() { internalProcedure(this, "__io_OutputStream_constructor__", new Block((Body) () -> @@ -103,7 +107,7 @@ } @LegacySignature(type = Type.GETTER, name = "Closed") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public logical getClosed() { return function(this, "Closed", logical.class, new Block((Body) () -> @@ -113,24 +117,26 @@ } @LegacySignature(type = Type.METHOD, name = "Close") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void close() { - internalProcedure(this, "Close", new Block()); + internalProcedure(this, "Close", new Block((Body)() -> { + this.closed.assign(true); + })); } @LegacySignature(type = Type.METHOD, name = "Write", parameters = { @LegacyParameter(name = "source-data", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public abstract int64 write(final character _sourceData); @LegacySignature(type = Type.METHOD, name = "Write", parameters = { @LegacyParameter(name = "source-data", type = "LONGCHAR", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public abstract int64 write(final longchar _sourceData); @LegacySignature(type = Type.METHOD, name = "Write", parameters = @@ -139,30 +145,48 @@ @LegacyParameter(name = "offset", type = "INT64", mode = "INPUT"), @LegacyParameter(name = "length", type = "INT64", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public abstract int64 write(final memptr _sourceData, final int64 _offset, final int64 _length); @LegacySignature(type = Type.METHOD, name = "Write", parameters = { @LegacyParameter(name = "source-data", type = "MEMPTR", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public int64 write(final memptr _sourceData) { memptr sourceData = TypeFactory.initInput(_sourceData); - return function(this, "Write", int64.class, new Block()); + return function(this, "Write", int64.class, new Block((Body)() -> { + if (closed.booleanValue()) + { + ErrorManager.recordOrThrowError(18196, "Cannot invoke method 'Write' after stream has been closed", false); + } + if (sourceData.isUninitialized()) + { + ErrorManager.recordOrThrowError(18193, "Invalid value specified for parameter 'source' of method or constructor 'Write'.", false); + } + + returnNormal(write(sourceData, new int64(1), sourceData.length())); + })); } @LegacySignature(type = Type.METHOD, name = "Write", parameters = { @LegacyParameter(name = "phData", type = "HANDLE", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public abstract int64 write(handle _phData); + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public int64 write(handle _phData) + { + return function(InputStream.class, this, "Write", int64.class, new Block((Body) () -> { + ErrorManager.recordOrThrowError(18192, + "Cannot invoke Write method in 'Progress.IO.OutputStream' because it is not implemented", + false); + })); + } @LegacySignature(type = Type.METHOD, name = "Flush") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void flush() { internalProcedure(this, "Flush", new Block()); === modified file 'src/com/goldencode/p2j/oo/json/JsonBackend.java' --- src/com/goldencode/p2j/oo/json/JsonBackend.java 2019-10-28 14:29:08 +0000 +++ src/com/goldencode/p2j/oo/json/JsonBackend.java 2021-01-29 08:33:05 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 HC 20190701 Initial version. ** 002 HC 20190714 Added more serializable number types. + ** 003 ME 20210128 Escape forward slash as in 4GL, json data type names. */ /* @@ -65,9 +66,10 @@ package com.goldencode.p2j.oo.json; import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.io.CharacterEscapes; +import com.fasterxml.jackson.core.io.SerializedString; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.util.*; -import com.goldencode.p2j.*; import com.goldencode.p2j.oo.json.objectmodel.*; import com.goldencode.p2j.util.*; @@ -142,10 +144,9 @@ // put on new line gen.setPrettyPrinter(new DefaultPrettyPrinter()); } - else - { - gen.setPrettyPrinter(new MinimalPrettyPrinter()); - } + + // 4GL escapes forward slash + gen.setCharacterEscapes(new ProCharacterEscapes()); writeConstruct(gen, construct); gen.flush(); gen.close(); @@ -159,18 +160,13 @@ * The source text to parse. * * @return json construct instance. + * @throws IOException + * @throws JsonParseException */ - public object parse(String source) + public object parse(String source) throws JsonParseException, IOException { - try - { JsonParser parser = factory.createParser(source); return parseImpl(parser); - } - catch (IOException e) - { - throw new RuntimeException(e); - } } /** @@ -180,19 +176,13 @@ * The input stream to parse. * * @return json construct instance. + * @throws IOException + * @throws JsonParseException */ - public object parse(InputStream source) + public object parse(InputStream source) throws JsonParseException, IOException { - try - { JsonParser parser = factory.createParser(source); return parseImpl(parser); - } - catch (IOException e) - { - // TODO: legacy error - throw new RuntimeException(e); - } } /** @@ -308,6 +298,33 @@ } /** + * Returns the string representation of object's corresponding JSON data type. + * + * @param int + * Json data type. + * + * @return the string value representing the JSON data type. + */ + public String getJsonDataTypeName(int type) + { + switch (type) + { + case 5: + return "array"; + case 4: + return "object"; + case 3: + return "boolean"; + case 2: + return "number"; + case 1: + return "string"; + default: + return "null"; + } + } + + /** * Implements serialization of the supplied json construct instance using the supplied json generator. * * @param jsonGen @@ -413,8 +430,9 @@ * Setup json parser. * * @return json construct instance. + * @throws JsonParseException */ - private object parseImpl(JsonParser parser) + private object parseImpl(JsonParser parser) throws JsonParseException { try { @@ -481,8 +499,7 @@ } catch (IOException ex) { - ErrorManager.recordOrThrowError(-1, "I/O failure.", new NumberedException(ex)); - return null; + throw new JsonParseException(parser, ex.getMessage(), ex); } } @@ -522,4 +539,35 @@ throw new RuntimeException("Unsupported encoding " + legacyEncoding); } } + + private class ProCharacterEscapes extends CharacterEscapes { + + private static final long serialVersionUID = 1L; + private final SerializedString fwdSlash; + private final int[] asciiEscapes; + + public ProCharacterEscapes() + { + fwdSlash = new SerializedString("\\/"); + asciiEscapes = standardAsciiEscapesForJSON(); + asciiEscapes['/'] = CharacterEscapes.ESCAPE_CUSTOM; + } + + @Override + public int[] getEscapeCodesForAscii() + { + return asciiEscapes; + } + + @Override + public SerializableString getEscapeSequence(int ch) + { + if (ch == '/') + return fwdSlash; + + return null; + } + + + } } === modified file 'src/com/goldencode/p2j/oo/json/JsonError.java' --- src/com/goldencode/p2j/oo/json/JsonError.java 2019-10-25 06:10:14 +0000 +++ src/com/goldencode/p2j/oo/json/JsonError.java 2021-01-15 13:04:56 +0000 @@ -8,6 +8,7 @@ ** 001 GES 20190227 First version. ** 002 CA 20190423 Added LegacyResource annotation. ** 003 GES 20191024 Added method support levels and updated the class support level. +** 004 ME 20210111 Added ctors and APIs to create new instance. */ /* @@ -112,4 +113,55 @@ __lang_SysError_constructor__(); })); } + + /** + * Explicit method associated with a legacy constructor for the + * Progress.Json.JsonError class. + * + * @param _msg + * The message. + * @param _num + * The message number. + */ + @LegacySignature(type = Type.CONSTRUCTOR, parameters = + { + @LegacyParameter(name = "msg", type = "CHARACTER", mode = "INPUT"), + @LegacyParameter(name = "num", type = "INTEGER", mode = "INPUT"), + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void __json_JsonError_constructor__(character msg, integer num) + { + internalProcedure(this, "__json_JsonError_constructor__", new Block((Body) () -> + { + // build the error message + __lang_SysError_constructor__(new character(ErrorManager.buildErrorText((int) num.getValue(), msg.getValue(), false, false)), num); + })); + } + + /** + * Create a new JsonError instance and return it as a legacy object. + * + * @param msg + * The error message. + * @param num + * The error number. + */ + public static object newInstance(character msg, integer num) + { + return ObjectOps.newInstance(JsonError.class, "II", msg, num); + } + + /** + * Create a new JsonError instance and return it as a legacy object. + * + * @param msg + * The error message. + * @param num + * The error number. + */ + public static object newInstance(String msg, int num) + { + return ObjectOps.newInstance(JsonError.class, "II", msg, num); + } + } \ No newline at end of file === modified file 'src/com/goldencode/p2j/oo/json/JsonParser.java' --- src/com/goldencode/p2j/oo/json/JsonParser.java 2019-10-24 23:19:26 +0000 +++ src/com/goldencode/p2j/oo/json/JsonParser.java 2021-01-14 09:46:31 +0000 @@ -10,6 +10,7 @@ ** 003 CA 20190423 Added LegacyResource annotation. ** 004 CA 20190527 Added annotations for property accessors and class event methods. ** 005 CA 20191024 Added method support levels and updated the class support level. +** 006 ME 20210114 Added on error undo, throw. */ /* @@ -68,6 +69,8 @@ package com.goldencode.p2j.oo.json; import com.goldencode.p2j.util.*; +import com.goldencode.p2j.util.BlockManager.Action; +import com.goldencode.p2j.util.BlockManager.Condition; import com.goldencode.p2j.oo.lang.*; import static com.goldencode.p2j.util.BlockManager.*; @@ -93,8 +96,7 @@ { externalProcedure(JsonParser.this, new Block((Body) () -> { - { - } + onBlockLevel(Condition.ERROR, Action.THROW); })); } === modified file 'src/com/goldencode/p2j/oo/json/JsonParserError.java' --- src/com/goldencode/p2j/oo/json/JsonParserError.java 2019-10-25 06:10:14 +0000 +++ src/com/goldencode/p2j/oo/json/JsonParserError.java 2021-01-11 12:48:03 +0000 @@ -9,6 +9,7 @@ ** 002 CA 20190423 Added LegacyResource annotation. ** 003 CA 20190527 Added annotations for property accessors and class event methods. ** 004 GES 20191024 Added method support levels and updated the class support level. +** 005 ME 20210111 Added ctors and APIs to create new instance. */ /* @@ -67,7 +68,6 @@ package com.goldencode.p2j.oo.json; import com.goldencode.p2j.util.*; -import com.goldencode.p2j.oo.lang.*; import static com.goldencode.p2j.util.BlockManager.*; import static com.goldencode.p2j.report.ReportConstants.*; @@ -82,7 +82,7 @@ extends JsonError { /** Offset flag. */ - private integer offset = UndoableFactory.integer(); + private integer offset = TypeFactory.integer(); /** * Default external procedure method which exists to ensure that any @@ -116,7 +116,30 @@ __json_JsonError_constructor__(); })); } - + + /** + * Explicit method associated with a legacy constructor for the + * Progress.Json.JsonParserError class. + * + * @param _msg + * The message. + * @param _num + * The message number. + */ + @LegacySignature(type = Type.CONSTRUCTOR, parameters = + { + @LegacyParameter(name = "msg", type = "CHARACTER", mode = "INPUT"), + @LegacyParameter(name = "num", type = "INTEGER", mode = "INPUT"), + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void __json_JsonParserError_constructor__(character msg, integer num) + { + internalProcedure(this, "__json_JsonError_constructor__", new Block((Body) () -> + { + __json_JsonError_constructor__(msg, num); + })); + } + /** * Reads the offset property. * @@ -152,4 +175,30 @@ offset.assign(var); })); } + + /** + * Create a new JsonParserError instance and return it as a legacy object. + * + * @param msg + * The error message. + * @param num + * The error number. + */ + public static object newInstance(character msg, integer num) + { + return ObjectOps.newInstance(JsonParserError.class, "II", msg, num); + } + + /** + * Create a new JsonParserError instance and return it as a legacy object. + * + * @param msg + * The error message. + * @param num + * The error number. + */ + public static object newInstance(String msg, int num) + { + return ObjectOps.newInstance(JsonParserError.class, "II", msg, num); + } } === modified file 'src/com/goldencode/p2j/oo/json/objectmodel/JsonArray.java' --- src/com/goldencode/p2j/oo/json/objectmodel/JsonArray.java 2019-10-24 23:19:26 +0000 +++ src/com/goldencode/p2j/oo/json/objectmodel/JsonArray.java 2021-01-31 10:14:52 +0000 @@ -12,6 +12,7 @@ ** 005 CA 20190706 Added Write(OUTPUT target AS CHARACTER). ** 006 HC 20190701 Implemented most of the legacy methods. ** 007 CA 20191024 Added method support levels and updated the class support level. +** 008 ME 20210130 Add missing methods (OE12.2), implement error handling 4GL compatible. */ /* @@ -71,11 +72,17 @@ import com.goldencode.p2j.oo.json.*; import com.goldencode.p2j.oo.lang.*; +import com.goldencode.p2j.persist.BufferReference; +import com.goldencode.p2j.persist.TempTable; +import com.goldencode.p2j.persist.TemporaryBuffer; +import com.goldencode.p2j.persist.serial.JsonExport; import com.goldencode.p2j.security.*; import com.goldencode.p2j.util.*; +import com.goldencode.p2j.util.ErrorManager; +import com.goldencode.p2j.util.BlockManager.Action; +import com.goldencode.p2j.util.BlockManager.Condition; import java.io.*; -import java.time.format.*; import java.util.*; import java.util.function.*; import java.util.logging.*; @@ -88,7 +95,7 @@ * Implementation of the Progress.Json.Objectmodel.JsonArray builtin class. */ @LegacyResource(resource = "Progress.Json.Objectmodel.JsonArray") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL_RESTR|RT_LVL_FULL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL_RESTR|RT_LVL_PARTIAL) public class JsonArray extends JsonConstruct { @@ -102,7 +109,7 @@ { protected integer initialValue() { - return UndoableFactory.integer(); + return TypeFactory.integer(-1L); } }; @@ -110,12 +117,20 @@ { externalProcedure(JsonArray.this, new Block((Body) () -> { - { - } + onBlockLevel(Condition.ERROR, Action.THROW); })); } @LegacySignature(type = Type.CONSTRUCTOR) + public static void __json_objectmodel_JsonArray_constructor__static__() + { + externalProcedure(JsonArray.class, new Block((Body) () -> + { + onBlockLevel(Condition.ERROR, Action.THROW); + })); + } + + @LegacySignature(type = Type.CONSTRUCTOR) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __json_objectmodel_JsonArray_constructor__() { @@ -138,16 +153,13 @@ { __json_objectmodel_JsonConstruct_constructor__(); - if (BaseDataType.isAllKnown(sz)) + if (sz.isUnknown() || sz.intValue() < 0) { - int size = sz.intValue(); - if (size >= 0) - { - Object[] values = new Object[size]; - Arrays.fill(values, null); - elements = Arrays.asList(values); - } + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("initial-size", this, + "JsonArray", "Can not be less than 0 or UNKNOWN (?)."), 16074)); } + + setLength(sz); })); } @@ -156,21 +168,12 @@ @LegacyParameter(name = "val", type = "CHARACTER", extent = -1, mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public void __json_objectmodel_JsonArray_constructor__(final character[] _val) + public void __json_objectmodel_JsonArray_constructor__(final character[] val) { - character[] val = TypeFactory.initInput(_val); - internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - addElementsCtorImpl(val); - } + addElementsCtorImpl(val); })); } @@ -186,14 +189,7 @@ internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - addElementsCtorImpl(val); - } + addElementsCtorImpl(val); })); } @@ -209,15 +205,7 @@ internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - addElementsCtorImpl(val); - } + addElementsCtorImpl(val); })); } @@ -233,14 +221,7 @@ internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - addElementsCtorImpl(val); - } + addElementsCtorImpl(val); })); } @@ -256,14 +237,7 @@ internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - addElementsCtorImpl(val); - } + addElementsCtorImpl(val); })); } @@ -279,14 +253,7 @@ internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - addElementsCtorImpl(val); - } + addElementsCtorImpl(val); })); } @@ -302,14 +269,7 @@ internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - addElementsCtorImpl(val); - } + addElementsCtorImpl(val); })); } @@ -325,14 +285,7 @@ internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - addElementsCtorImpl(val); - } + addElementsCtorImpl(val); })); } @@ -348,14 +301,7 @@ internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - addElementsCtorImpl(val); - } + addElementsCtorImpl(val); })); } @@ -371,14 +317,7 @@ internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - addElementsCtorImpl(val); - } + addElementsCtorImpl(val); })); } @@ -394,14 +333,7 @@ internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - addElementsCtorImpl(val); - } + addElementsCtorImpl(val); })); } @@ -417,14 +349,7 @@ internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - addElementsCtorImpl(val); - } + addElementsCtorImpl(val); })); } @@ -440,14 +365,7 @@ internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - addElementsCtorImpl(val); - } + addElementsCtorImpl(val); })); } @@ -463,14 +381,7 @@ internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - addElementsCtorImpl(val); - } + addElementsCtorImpl(val); })); } @@ -486,14 +397,7 @@ internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - addElementsCtorImpl(val); - } + addElementsCtorImpl(val); })); } @@ -509,19 +413,10 @@ internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - for (object obj : val) - { - addElement(obj.ref()); - } - } + addElementsCtorImpl(val); })); } + /** TODO: overloaded c'tors! @LegacySignature(type = Type.CONSTRUCTOR, parameters = @@ -535,10 +430,7 @@ internalProcedure(this, "__json_objectmodel_JsonArray_constructor__", new Block((Body) () -> { __json_objectmodel_JsonConstruct_constructor__(); - for (object obj : val) - { - addElement(null, obj.ref()); - } + addElementsCtorImpl(val); })); } */ @@ -589,36 +481,31 @@ internalProcedure(this, "Length", new Block((Body) () -> { - if (!var.isUnknown()) - { - int newLength = var.intValue(); - if (newLength < 0) - { - returnError(ObjectOps.newInstance(JsonError.class)); - return; - } - - int size = elements.size(); - if (newLength == size) - { - return; - } - - if (newLength < size) - { - List sublist = elements.subList(0, newLength); - elements = new ArrayList<>(newLength); - elements.addAll(sublist); - } - else - { - ArrayList newList = new ArrayList<>(newLength); - newList.addAll(elements); - Object[] nulls = new Object[newLength - elements.size()]; - Arrays.fill(nulls, null); - newList.add(nulls); - elements = newList; - } + if (var.isUnknown() || var.intValue() < 0) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("length", this, + "Length", "Can not be less than 0 or UNKNOWN (?)."), 16074)); + } + + int newLength = var.intValue(); + int size = elements.size(); + + if (newLength == size) + { + return; + } + + if (newLength < size) + { + List sublist = elements.subList(0, newLength); + elements = new ArrayList<>(newLength); + elements.addAll(sublist); + } + else + { + Object[] nulls = new Object[newLength - elements.size()]; + Arrays.fill(nulls, null); + elements.addAll(Arrays.asList(nulls)); } })); } @@ -1153,6 +1040,23 @@ @LegacySignature(type = Type.METHOD, name = "Add", parameters = { @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "val", type = "CHARACTER", mode = "INPUT", extent = -1) + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public integer add(final integer _idx, final character[] _val) + { + integer idx = TypeFactory.initInput(_idx); + character[] val = TypeFactory.initInput(_val); + + return function(this, "Add", integer.class, new Block((Body) () -> + { + addElementsImpl(idx, val); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Add", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), @LegacyParameter(name = "val", type = "COMHANDLE", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @@ -1183,6 +1087,23 @@ addElementImpl(idx, val); })); } + + @LegacySignature(type = Type.METHOD, name = "Add", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "val", type = "DATE", mode = "INPUT", extent = -1) + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public integer add(final integer _idx, final date[] _val) + { + integer idx = TypeFactory.initInput(_idx); + date[] val = TypeFactory.initInput(_val); + + return function(this, "Add", integer.class, new Block((Body) () -> + { + addElementsImpl(idx, val); + })); + } @LegacySignature(type = Type.METHOD, name = "Add", parameters = { @@ -1200,6 +1121,23 @@ addElementImpl(idx, val); })); } + + @LegacySignature(type = Type.METHOD, name = "Add", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "val", type = "DATETIME", mode = "INPUT", extent = -1) + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public integer add(final integer _idx, final datetime[] _val) + { + integer idx = TypeFactory.initInput(_idx); + datetime[] val = TypeFactory.initInput(_val); + + return function(this, "Add", integer.class, new Block((Body) () -> + { + addElementsImpl(idx, val); + })); + } @LegacySignature(type = Type.METHOD, name = "Add", parameters = { @@ -1221,6 +1159,23 @@ @LegacySignature(type = Type.METHOD, name = "Add", parameters = { @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "val", type = "DATETIMETZ", mode = "INPUT", extent = -1) + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public integer add(final integer _idx, final datetimetz[] _val) + { + integer idx = TypeFactory.initInput(_idx); + datetimetz[] val = TypeFactory.initInput(_val); + + return function(this, "Add", integer.class, new Block((Body) () -> + { + addElementsImpl(idx, val); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Add", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), @LegacyParameter(name = "val", type = "DECIMAL", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @@ -1238,6 +1193,23 @@ @LegacySignature(type = Type.METHOD, name = "Add", parameters = { @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "val", type = "DECIMAL", mode = "INPUT", extent = -1) + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public integer add(final integer _idx, final decimal[] _val) + { + integer idx = TypeFactory.initInput(_idx); + decimal[] val = TypeFactory.initInput(_val); + + return function(this, "Add", integer.class, new Block((Body) () -> + { + addElementsImpl(idx, val); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Add", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), @LegacyParameter(name = "val", type = "HANDLE", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @@ -1255,6 +1227,23 @@ @LegacySignature(type = Type.METHOD, name = "Add", parameters = { @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "val", type = "HANDLE", mode = "INPUT", extent = -1) + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public integer add(final integer _idx, final handle[] _val) + { + integer idx = TypeFactory.initInput(_idx); + handle[] val = TypeFactory.initInput(_val); + + return function(this, "Add", integer.class, new Block((Body) () -> + { + addElementsImpl(idx, val); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Add", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), @LegacyParameter(name = "val", type = "INT64", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @@ -1272,6 +1261,23 @@ @LegacySignature(type = Type.METHOD, name = "Add", parameters = { @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "val", type = "INT64", mode = "INPUT", extent = -1) + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public integer add(final integer _idx, final int64[] _val) + { + integer idx = TypeFactory.initInput(_idx); + int64[] val = TypeFactory.initInput(_val); + + return function(this, "Add", integer.class, new Block((Body) () -> + { + addElementsImpl(idx, val); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Add", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), @LegacyParameter(name = "val", type = "INTEGER", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @@ -1289,6 +1295,23 @@ @LegacySignature(type = Type.METHOD, name = "Add", parameters = { @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "val", type = "INTEGER", mode = "INPUT", extent = -1) + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public integer add(final integer _idx, final integer[] _val) + { + integer idx = TypeFactory.initInput(_idx); + integer[] val = TypeFactory.initInput(_val); + + return function(this, "Add", integer.class, new Block((Body) () -> + { + addElementsImpl(idx, val); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Add", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), @LegacyParameter(name = "val", type = "LOGICAL", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @@ -1306,6 +1329,23 @@ @LegacySignature(type = Type.METHOD, name = "Add", parameters = { @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "val", type = "LOGICAL", mode = "INPUT", extent = -1) + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public integer add(final integer _idx, final logical[] _val) + { + integer idx = TypeFactory.initInput(_idx); + logical[] val = TypeFactory.initInput(_val); + + return function(this, "Add", integer.class, new Block((Body) () -> + { + addElementsImpl(idx, val); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Add", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), @LegacyParameter(name = "val", type = "LONGCHAR", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @@ -1323,6 +1363,23 @@ @LegacySignature(type = Type.METHOD, name = "Add", parameters = { @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "val", type = "LONGCHAR", mode = "INPUT", extent = -1) + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public integer add(final integer _idx, final longchar[] _val) + { + integer idx = TypeFactory.initInput(_idx); + longchar[] val = TypeFactory.initInput(_val); + + return function(this, "Add", integer.class, new Block((Body) () -> + { + addElementsImpl(idx, val); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Add", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), @LegacyParameter(name = "val", type = "MEMPTR", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @@ -1340,6 +1397,23 @@ @LegacySignature(type = Type.METHOD, name = "Add", parameters = { @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "val", type = "MEMPTR", mode = "INPUT", extent = -1) + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public integer add(final integer _idx, final memptr[] _val) + { + integer idx = TypeFactory.initInput(_idx); + memptr[] val = TypeFactory.initInput(_val); + + return function(this, "Add", integer.class, new Block((Body) () -> + { + addElementsImpl(idx, val); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Add", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), @LegacyParameter(name = "val", type = "RAW", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @@ -1357,6 +1431,23 @@ @LegacySignature(type = Type.METHOD, name = "Add", parameters = { @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "val", type = "RAW", mode = "INPUT", extent = -1) + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public integer add(final integer _idx, final raw[] _val) + { + integer idx = TypeFactory.initInput(_idx); + raw[] val = TypeFactory.initInput(_val); + + return function(this, "Add", integer.class, new Block((Body) () -> + { + addElementsImpl(idx, val); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Add", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), @LegacyParameter(name = "val", type = "RECID", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @@ -1374,6 +1465,23 @@ @LegacySignature(type = Type.METHOD, name = "Add", parameters = { @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "val", type = "RECID", mode = "INPUT", extent = -1) + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public integer add(final integer _idx, final recid[] _val) + { + integer idx = TypeFactory.initInput(_idx); + recid[] val = TypeFactory.initInput(_val); + + return function(this, "Add", integer.class, new Block((Body) () -> + { + addElementsImpl(idx, val); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Add", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), @LegacyParameter(name = "val", type = "ROWID", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @@ -1391,6 +1499,23 @@ @LegacySignature(type = Type.METHOD, name = "Add", parameters = { @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "val", type = "ROWID", mode = "INPUT", extent = -1) + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public integer add(final integer _idx, final rowid[] _val) + { + integer idx = TypeFactory.initInput(_idx); + rowid[] val = TypeFactory.initInput(_val); + + return function(this, "Add", integer.class, new Block((Body) () -> + { + addElementsImpl(idx, val); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Add", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), @LegacyParameter(name = "val", type = "OBJECT", qualified = "progress.json.objectmodel.jsonarray", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @@ -1405,6 +1530,24 @@ })); } + + @LegacySignature(type = Type.METHOD, name = "Add", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "val", type = "OBJECT", qualified = "progress.json.objectmodel.jsonarray", mode = "INPUT", extent = -1) + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public integer add(final integer _idx, final object[] _val) + { + integer idx = TypeFactory.initInput(_idx); + object[] val = TypeFactory.initInput(_val); + + return function(this, "Add", integer.class, new Block((Body) () -> + { + addElementsImpl(idx, val); + })); + } + @LegacySignature(type = Type.METHOD, name = "Add", parameters = { @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), @@ -1422,6 +1565,23 @@ })); } + @LegacySignature(type = Type.METHOD, name = "Add", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "val", type = "OBJECT", qualified = "progress.json.objectmodel.jsonobject", mode = "INPUT", extent = -1) + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public integer add_1(final integer _idx, final object[] _val) + { + integer idx = TypeFactory.initInput(_idx); + object[] val = TypeFactory.initInput(_val); + + return function(this, "Add", integer.class, new Block((Body) () -> + { + addElementsImpl(idx, val); + })); + } + @LegacySignature(type = Type.METHOD, name = "AddNull") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public integer addNull() @@ -1444,13 +1604,16 @@ return function(this, "AddNull", integer.class, new Block((Body) () -> { - if (count == null || count.isUnknown() || count.intValue() < 1) + int cnt = count.isUnknown() ? 0 : count.intValue(); + + if (cnt < 1) { - returnError(ObjectOps.newInstance(JsonError.class)); + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("count", this, + "AddNull", "Can not be less than 1 or UNKNOWN (?)."), 16074)); } else { - for (int i = 0; i < count.intValue(); i++) + for (int i = 0; i < cnt; i++) { addElement((Object) null); } @@ -1472,16 +1635,24 @@ return function(this, "AddNull", integer.class, new Block((Body) () -> { - if (!checkValidIndex(idx) || count == null || count.isUnknown() || count.intValue() < 1) - { - returnError(ObjectOps.newInstance(JsonError.class)); + int idx2 = idx.isUnknown() ? 0 : idx.intValue(); + int cnt = count.isUnknown() ? 0 : count.intValue(); + + if (idx2 < 1 || idx2 > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("index", this, + "AddNull", "Can not be less than 0, UNKNOWN (?) or larger than the size of the array."), 16073)); + } + else if (cnt < 1) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("count", this, + "AddNull", "Can not be less than 1 or UNKNOWN (?)."), 16074)); } else { - int idx2 = idx.intValue(); - for (int i = 0; i < count.intValue(); i++) + for (int i = 0; i < cnt; i++) { - addElement(idx2, (Object) null); + addSetElementImpl(idx2, (Object) null, true); idx2++; } @@ -1495,29 +1666,10 @@ @LegacyParameter(name = "val", type = "CHARACTER", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public integer addNumber(final character _val) + public integer addNumber(final character val) { - character val = TypeFactory.initInput(_val); - - return function(this, "AddNumber", integer.class, new Block((Body) () -> - { - if (val == null || val.isUnknown() || val.toStringMessage().isEmpty()) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - try - { - integer i = new integer(val); - addElementImpl(i); - returnNormal(elements.size()); - } - catch (NumberFormatException e) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - } + return function(this, "AddNumber", integer.class, new Block((Body) () -> { + returnNormal(addNumber(new integer(elements.size()), val)); })); } @@ -1532,27 +1684,7 @@ return function(this, "AddNumber", integer.class, new Block((Body) () -> { - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - try - { - for (character ch : val) - { - integer i = new integer(ch); - addElementImpl(i); - } - - returnNormal(elements.size()); - } - catch (NumberFormatException e) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - } + returnNormal(addNumber(new integer(elements.size()), val)); })); } @@ -1569,29 +1701,26 @@ return function(this, "AddNumber", integer.class, new Block((Body) () -> { - if (!checkValidIndex(idx)) + int pos = idx == null || idx.isUnknown() ? -1 : idx.intValue(); + + // index zero means add it to the start + if (pos < 0 || pos > elements.size()) { - returnError(ObjectOps.newInstance(JsonError.class)); - return; + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("index", this, + "AddNumber", "Can not be less than 0, UNKNOWN (?) or larger than the size of the array."), 16073)); } - if (val == null || val.isUnknown() || val.toStringMessage().isEmpty()) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - try - { - integer i = new integer(val); - addElementImpl(idx, i); - returnNormal(elements.size()); - } - catch (NumberFormatException e) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - } + try + { + addSetElementImpl(pos, val.isUnknown() ? (Object) null : Double.parseDouble(val.getValue()), true); + } + catch (Exception e) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("value", this, + "AddNumber", "Not a valid JSON number."), 16053)); + } + + returnNormal(pos + 1); })); } @@ -1607,34 +1736,35 @@ return function(this, "AddNumber", integer.class, new Block((Body) () -> { - if (!checkValidIndex(idx)) - { - returnError(ObjectOps.newInstance(JsonError.class)); - return; - } - - if (val == null) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - try - { - int i = idx.intValue(); - for (BaseDataType value : val) - { - addElementImpl(new integer(i), value); - i++; - } - - returnNormal(elements.size()); - } - catch (NumberFormatException e) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - } + int pos = idx == null || idx.isUnknown() ? -1 : idx.intValue(); + + // index zero means add it to the start + if (pos < 0 || pos > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("index", this, + "AddNumber", "Can not be less than 0, UNKNOWN (?) or larger than the size of the array."), 16073)); + } + + if (val == null || val.length == 0) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("array-value", this, + "AddNumber", "Can not be an indeterminate array."), 16081)); + } + + try + { + for (int i = 0; i < val.length; i++) + { + addSetElementImpl(pos + i, val[i].isUnknown() ? (Object) null : Double.parseDouble(val[i].getValue()), true); + } + } + catch (Exception e) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("value", this, + "AddNumber", "Not a valid JSON number."), 16053)); + } + + returnNormal(pos + val.length); })); } @@ -1650,9 +1780,9 @@ { if (val instanceof JsonConstruct) { - val = ((JsonConstruct) val).clone(); + val = ((JsonConstruct) val).clone().ref(); } - cloned.ref().elements.add(val); + cloned.ref().addElement(val); } returnNormal(cloned); @@ -1670,7 +1800,7 @@ return function(this, "GetCharacter", character.class, new Block((Body) () -> { - getElementImpl(idx, o -> new character((String) o), character::new); + getElementImpl(idx, "GetCharacter", 1, o -> new character((String) o), unknown::new); })); } @@ -1687,7 +1817,7 @@ return extentFunction(this, "GetCharacter", character.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> new character((String) o), character::new); + getElementsImpl(idx, count, "GetCharacter", 1, o -> new character((String) o), character::new); })); } @@ -1702,7 +1832,7 @@ return function(this, "GetCOMHandle", comhandle.class, new Block((Body) () -> { - getElementImpl(idx, o -> comhandle.fromResourceId(((Number) o).longValue()), comhandle::new); + getElementImpl(idx, "GetCOMHandle", 2, o -> comhandle.fromResourceId(((Number) o).longValue()), comhandle::new); })); } @@ -1719,7 +1849,7 @@ return extentFunction(this, "GetCOMHandle", comhandle.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> comhandle.fromResourceId(((Number) o).longValue()), comhandle::new); + getElementsImpl(idx, count, "GetCOMHandle", 2, o -> comhandle.fromResourceId(((Number) o).longValue()), comhandle::new); })); } @@ -1734,7 +1864,7 @@ return function(this, "GetDate", date.class, new Block((Body) () -> { - getElementImpl(idx, o -> date.parseIsoDate((String) o), date::new); + getElementImpl(idx, "GetDate", 1, o -> date.parseIsoDate((String) o), date::new); })); } @@ -1751,7 +1881,7 @@ return extentFunction(this, "GetDate", date.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> date.parseIsoDate((String) o), date::new); + getElementsImpl(idx, count, "GetDate", 1, o -> date.parseIsoDate((String) o), date::new); })); } @@ -1766,7 +1896,7 @@ return function(this, "GetDatetime", datetime.class, new Block((Body) () -> { - getElementImpl(idx, o -> date.parseIsoDate((String) o), datetime::new); + getElementImpl(idx, "GetDatetime", 1, o -> date.parseIsoDate((String) o), datetime::new); })); } @@ -1783,7 +1913,7 @@ return extentFunction(this, "GetDatetime", datetime.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> date.parseIsoDate((String) o), datetime::new); + getElementsImpl(idx, count, "GetDatetime", 1, o -> date.parseIsoDate((String) o), datetime::new); })); } @@ -1798,7 +1928,7 @@ return function(this, "GetDatetimeTZ", datetimetz.class, new Block((Body) () -> { - getElementImpl(idx, o -> date.parseIsoDate((String) o), datetimetz::new); + getElementImpl(idx, "GetDatetimeTZ", 1, o -> date.parseIsoDate((String) o), datetimetz::new); })); } @@ -1815,7 +1945,7 @@ return extentFunction(this, "GetDatetimeTZ", datetimetz.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> date.parseIsoDate((String) o), datetimetz::new); + getElementsImpl(idx, count, "GetDatetimeTZ", 1, o -> date.parseIsoDate((String) o), datetimetz::new); })); } @@ -1830,7 +1960,7 @@ return function(this, "GetDecimal", decimal.class, new Block((Body) () -> { - getElementImpl(idx, o -> new decimal((Number) o), decimal::new); + getElementImpl(idx, "GetDecimal", 2, o -> new decimal((Number) o), decimal::new); })); } @@ -1847,7 +1977,7 @@ return extentFunction(this, "GetDecimal", decimal.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> new decimal((Number) o), decimal::new); + getElementsImpl(idx, count, "GetDecimal", 2, o -> new decimal((Number) o), decimal::new); })); } @@ -1862,7 +1992,7 @@ return function(this, "GetHandle", handle.class, new Block((Body) () -> { - getElementImpl(idx, o -> handle.fromResourceId(((Number) o).longValue()), handle::new); + getElementImpl(idx, "GetHandle", 2, o -> handle.fromResourceId(((Number) o).longValue()), handle::new); })); } @@ -1879,7 +2009,7 @@ return extentFunction(this, "GetHandle", handle.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> handle.fromResourceId(((Number) o).longValue()), handle::new); + getElementsImpl(idx, count, "GetHandle", 2, o -> handle.fromResourceId(((Number) o).longValue()), handle::new); })); } @@ -1894,7 +2024,7 @@ return function(this, "GetInt64", int64.class, new Block((Body) () -> { - getElementImpl(idx, o -> new int64((Number) o), int64::new); + getElementImpl(idx, "GetInt64", 2, o -> new int64((Number) o), int64::new); })); } @@ -1911,7 +2041,7 @@ return extentFunction(this, "GetInt64", int64.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> new int64((Number) o), int64::new); + getElementsImpl(idx, count, "GetInt64", 2, o -> new int64((Number) o), int64::new); })); } @@ -1926,7 +2056,7 @@ return function(this, "GetInteger", integer.class, new Block((Body) () -> { - getElementImpl(idx, o -> new integer((Number) o), integer::new); + getElementImpl(idx, "GetInteger", 2, o -> new integer((Number) o), integer::new); })); } @@ -1943,7 +2073,7 @@ return extentFunction(this, "GetInteger", integer.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> new integer((Number) o), integer::new); + getElementsImpl(idx, count, "GetInteger", 2, o -> new integer((Number) o), integer::new); })); } @@ -1958,7 +2088,7 @@ return function(this, "GetJsonArray", object.class, new Block((Body) () -> { - getElementImpl(idx, o -> new object((JsonArray) o), object::new); + getElementImpl(idx, "GetJsonArray", 5, o -> new object((JsonArray) o), object::new); })); } @@ -1975,7 +2105,7 @@ return extentFunction(this, "GetJsonArray", object.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> new object((JsonArray) o), object::new); + getElementsImpl(idx, count, "GetJsonArray", 5, o -> new object((JsonArray) o), object::new); })); } @@ -1990,7 +2120,7 @@ return function(this, "GetJsonObject", object.class, new Block((Body) () -> { - getElementImpl(idx, o -> new object((JsonObject) o), object::new); + getElementImpl(idx, "GetJsonObject", 4, o -> new object((JsonObject) o), object::new); })); } @@ -2007,7 +2137,7 @@ return extentFunction(this, "GetJsonObject", object.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> new object((JsonObject) o), object::new); + getElementsImpl(idx, count, "GetJsonObject", 4, o -> new object((JsonObject) o), object::new); })); } @@ -2029,21 +2159,27 @@ public longchar getJsonText(final integer _idx) { integer idx = TypeFactory.initInput(_idx); - - return function(this, "GetJsonText", longchar.class, new Block((Body) () -> - { - getElementImpl(idx, o -> - { - try - { - return getJsonText((JsonConstruct) o); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - }, - longchar::new); + + return function(this, "GetJsonText", longchar.class, new Block((Body) () -> { + int pos = idx == null || idx.isUnknown() ? -1 : idx.intValue(); + + if (pos < 1 || pos > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("index", this, + "GetJsonText", "Can not be less than 1, UNKNOWN (?) or larger than the size of the array."), 16073)); + } + + Object val = elements.get(idx.intValue() - 1); + + try + { + returnNormal(getJsonText(val)); + } + catch (IOException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } })); } @@ -2060,18 +2196,42 @@ return extentFunction(this, "GetJsonText", longchar.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> - { + int pos = idx == null || idx.isUnknown() ? -1 : idx.intValue(); + int cnt = count == null || count.isUnknown() ? -1 : count.intValue(); + + if (pos < 1 || pos > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("index", this, + "GetJsonText", + "Can not be less than 1, UNKNOWN (?) or larger than the size of the array."), + 16073)); + } + + if (cnt < 1 || pos + cnt > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("count", this, + "GetJsonText", + "Can not be less than 1, UNKNOWN (?) or larger than the size of the array."), + 16073)); + } + + longchar[] res = new longchar[cnt]; + for (int i = 0; i < cnt; i++) + { + Object val = elements.get(pos + i - 1); + try { - return getJsonText((JsonConstruct) o); + res[i] = getJsonText(val); } catch (IOException e) { - throw new RuntimeException(e); + // TODO Auto-generated catch block + e.printStackTrace(); } - }, - longchar::new); + } + + returnExtentNormal(res); })); } @@ -2086,7 +2246,7 @@ return function(this, "GetLogical", logical.class, new Block((Body) () -> { - getElementImpl(idx, o -> new logical((Boolean) o), logical::new); + getElementImpl(idx, "GetLogical", 3, o -> new logical((Boolean) o), logical::new); })); } @@ -2103,7 +2263,7 @@ return extentFunction(this, "GetLogical", logical.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> new logical((Boolean) o), logical::new); + getElementsImpl(idx, count, "GetLogical", 3, o -> new logical((Boolean) o), logical::new); })); } @@ -2118,7 +2278,7 @@ return function(this, "GetLongchar", longchar.class, new Block((Body) () -> { - getElementImpl(idx, o -> new longchar((String) o), longchar::new); + getElementImpl(idx, "GetLongchar", 1, o -> new longchar((String) o), longchar::new); })); } @@ -2135,7 +2295,7 @@ return extentFunction(this, "GetLongchar", longchar.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> new longchar((String) o), longchar::new); + getElementsImpl(idx, count, "GetLongchar", 1, o -> new longchar((String) o), longchar::new); })); } @@ -2152,10 +2312,13 @@ return function(this, "GetLongchar", longchar.class, new Block((Body) () -> { - getElementImpl(idx, o -> + getElementImpl(idx, "GetLongchar", 1, o -> { - longchar res = new longchar((String) o); - res.fixCodePage(cp); + longchar res = TypeFactory.longchar(); + if (!TextOps.isEmpty(cp)) + res.fixCodePage(cp); + res.assign(o); + return res; }, longchar::new); @@ -2177,10 +2340,13 @@ return extentFunction(this, "GetLongchar", longchar.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> + getElementsImpl(idx, count, "GetLongchar", 1, o -> { - longchar res = new longchar((String) o); - res.fixCodePage(cp); + longchar res = TypeFactory.longchar(); + if (!TextOps.isEmpty(cp)) + res.fixCodePage(cp); + res.assign(o); + return res; }, longchar::new); @@ -2198,7 +2364,7 @@ return function(this, "GetMemptr", memptr.class, new Block((Body) () -> { - getElementImpl(idx, o -> new memptr(Base64.getDecoder().decode((String) o)), memptr::new); + getElementImpl(idx, "GetMemptr", 1, o -> new memptr(Base64.getDecoder().decode((String) o)), unknown::new); })); } @@ -2215,7 +2381,7 @@ return extentFunction(this, "GetMemptr", memptr.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> new memptr(Base64.getDecoder().decode((String) o)), memptr::new); + getElementsImpl(idx, count, "GetMemptr", 1, o -> new memptr(Base64.getDecoder().decode((String) o)), unknown::new); })); } @@ -2230,7 +2396,7 @@ return function(this, "GetRaw", raw.class, new Block((Body) () -> { - getElementImpl(idx, + getElementImpl(idx, "GetRaw", 1, o -> new raw(Base64.getDecoder().decode((String) o)), raw::instantiateUnknownRaw); })); @@ -2251,6 +2417,7 @@ { getElementsImpl(idx, count, + "GetRaw", 1, o -> new raw(Base64.getDecoder().decode((String) o)), raw::instantiateUnknownRaw); })); @@ -2267,7 +2434,7 @@ return function(this, "GetRecid", recid.class, new Block((Body) () -> { - getElementImpl(idx, o -> new recid(((Number) o).longValue()), recid::new); + getElementImpl(idx, "GetRecid", 2, o -> new recid(((Number) o).longValue()), recid::new); })); } @@ -2284,7 +2451,7 @@ return extentFunction(this, "GetRecid", recid.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> new recid(((Number) o).longValue()), recid::new); + getElementsImpl(idx, count, "GetRecid", 2, o -> new recid(((Number) o).longValue()), recid::new); })); } @@ -2299,7 +2466,7 @@ return function(this, "GetRowid", rowid.class, new Block((Body) () -> { - getElementImpl(idx, o -> + getElementImpl(idx, "GetRowid", 1, o -> { Base64.Decoder dec = Base64.getDecoder(); return new rowid(Utils.bytesToLongLE(dec.decode((String) o))); @@ -2321,7 +2488,8 @@ return extentFunction(this, "GetRowid", rowid.class, new Block((Body) () -> { - getElementsImpl(idx, count, o -> new rowid(((Number) o).longValue()), rowid::new); + final Base64.Decoder dec = Base64.getDecoder(); + getElementsImpl(idx, count, "GetRowid", 1, o -> new rowid(Utils.bytesToLongLE(dec.decode((String) o))), rowid::new); })); } @@ -2336,15 +2504,16 @@ return function(this, "GetType", integer.class, new Block((Body) () -> { - if (checkValidIndex(idx)) - { - Object value = elements.get(idx.intValue() - 1); - returnNormal(new integer(JsonBackend.instance().getJsonDataType(value))); - } - else - { - returnError(ObjectOps.newInstance(JsonError.class)); - } + int pos = idx == null || idx.isUnknown() ? -1 : idx.intValue(); + + if (pos < 1 || pos > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("index", this, + "GetType", "Can not be less than 1, UNKNOWN (?) or larger than the size of the array."), 16073)); + } + + Object value = elements.get(pos - 1); + returnNormal(new integer(JsonBackend.instance().getJsonDataType(value))); })); } @@ -2359,15 +2528,18 @@ return function(this, "IsNull", logical.class, new Block((Body) () -> { - if (checkValidIndex(idx)) - { - Object val = elements.get(idx.intValue() - 1); + int idx2 = idx.isUnknown() ? 0 : idx.intValue(); + + if (idx2 < 1 || idx2 > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("index", this, + "IsNull", "Can not be less than 1, UNKNOWN (?) or larger than the size of the array."), 16073)); + } + else + { + Object val = elements.get(idx2 - 1); returnNormal(new logical(val == null)); } - else - { - returnError(ObjectOps.newInstance(JsonError.class)); - } })); } @@ -2376,57 +2548,57 @@ @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public logical remove(final integer _idx) + public logical remove(final integer idx) + { + return function(this, "Remove", logical.class, new Block((Body) () -> + { + returnNormal(remove(idx, new integer(1))); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Remove", parameters = + { + @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), + @LegacyParameter(name = "count", type = "INTEGER", mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public logical remove(final integer _idx, final integer _count) { integer idx = TypeFactory.initInput(_idx); + integer count = TypeFactory.initInput(_count); return function(this, "Remove", logical.class, new Block((Body) () -> { - if (checkValidIndex(idx)) - { - Object o = elements.remove(idx.intValue() - 1); + int pos = idx == null || idx.isUnknown() ? -1 : idx.intValue(); + int cnt = count == null || count.isUnknown() ? -1 : count.intValue(); + + if (pos < 1 || pos > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("index", this, + "Remove", + "Can not be less than 1, UNKNOWN (?) or larger than the size of the array."), + 16073)); + } + + if (cnt < 1 || pos + cnt > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("count", this, + "Remove", + "Can not be less than 1, UNKNOWN (?) or larger than the size of the array."), + 16073)); + } + + for (int i = 0; i < cnt; i++) + { + Object o = elements.remove(pos - 1); if (o instanceof JsonConstruct) { ObjectOps.decrement((_BaseObject_) o); } - returnNormal(new logical(true)); - } - else - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - })); - } - - @LegacySignature(type = Type.METHOD, name = "Remove", parameters = - { - @LegacyParameter(name = "idx", type = "INTEGER", mode = "INPUT"), - @LegacyParameter(name = "count", type = "INTEGER", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public logical remove(final integer _idx, final integer _count) - { - integer idx = TypeFactory.initInput(_idx); - integer count = TypeFactory.initInput(_count); - - return function(this, "Remove", logical.class, new Block((Body) () -> - { - if (checkValidIndexCount(idx, count)) - { - for (int i = 0; i < count.intValue(); i++) - { - Object o = elements.remove(idx.intValue() - 1); - if (o instanceof JsonConstruct) - { - ObjectOps.decrement((_BaseObject_) o); - } - } - returnNormal(new logical(true)); - } - else - { - returnError(ObjectOps.newInstance(JsonError.class)); - } + } + + returnNormal(new logical(true)); + })); } @@ -2708,7 +2880,7 @@ @LegacyParameter(name = "val", type = "OBJECT", qualified = "progress.json.objectmodel.jsonobject", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public logical set_2(final integer _idx, final object _val) { integer idx = TypeFactory.initInput(_idx); @@ -2731,7 +2903,18 @@ return function(this, "SetNull", logical.class, new Block((Body) () -> { - setElementImpl(idx, new unknown()); + int idx2 = idx.isUnknown() ? 0 : idx.intValue(); + + if (idx2 < 1 || idx2 > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("index", this, + "SetNull", "Can not be less than 1, UNKNOWN (?) or larger than the size of the array."), 16073)); + } + else + { + addSetElementImpl(idx2 - 1, (Object) null, false); + returnNormal(idx2 + 1); + } })); } @@ -2748,21 +2931,25 @@ return function(this, "SetNumber", logical.class, new Block((Body) () -> { - if (val == null || val.isUnknown() || val.toStringMessage().isEmpty()) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - try - { - setElementImpl(idx, val); - } - catch (NumberFormatException e) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - } + int pos = idx == null || idx.isUnknown() ? -1 : idx.intValue(); + + if (pos < 1 || pos > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("index", this, + "SetNumber", "Can not be less than 1, UNKNOWN (?) or larger than the size of the array."), 16073)); + } + + try + { + addSetElementImpl(pos - 1, val.isUnknown() ? null : Double.parseDouble(val.getValue()), false); + } + catch (Exception e) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("value", this, + "SetNumber", "Not a valid JSON number."), 16053)); + } + + returnNormal(pos + 1); })); } @@ -2869,16 +3056,15 @@ */ private void addElementsCtorImpl(BaseDataType[] elements) { - try + if (elements == null || elements.length == 0) { - for (BaseDataType element : elements) - { - addElement(JsonBackend.instance().convertLegacyValueToJson(element)); - } + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("initial-value", this, + "JsonArray", "Can not be an indeterminate array."), 16081)); } - catch (ClassCastException e) + + for (BaseDataType element : elements) { - returnError(ObjectOps.newInstance(JsonError.class)); + addElement(JsonBackend.instance().convertLegacyValueToJson(element)); } } @@ -2890,20 +3076,55 @@ */ private void addElementsImpl(BaseDataType[] elements) { - try - { - for (BaseDataType value : elements) - { - addElement(JsonBackend.instance().convertLegacyValueToJson(value)); - } - returnNormal(new integer(this.elements.size())); - } - catch (ClassCastException e) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - } - + addElementsImpl(new integer(this.elements.size()), elements); + } + + /** + * Implements the {@code add} legacy methods for adding multiple array elements to this instance. + * + * @param idx + * The 1-based array index where the element should be added. + * @param items + * The values to use as the initial json elements. + */ + private void addElementsImpl(integer idx, BaseDataType[] items) + { + returnNormal(addElements(idx, items)); + } + + /** + * Implements the {@code add} legacy methods for adding multiple array elements to this instance. + * + * @param idx + * The 1-based array index where the element should be added. + * @param items + * The values to use as the initial json elements. + */ + private int addElements(integer idx, BaseDataType[] items) + { + int pos = idx == null || idx.isUnknown() ? -1 : idx.intValue(); + + // index zero means add it to the start + if (pos < 0 || pos > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("index", this, + "Add", "Can not be less than 0, UNKNOWN (?) or larger than the size of the array."), 16073)); + } + + if (items == null || items.length == 0) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("array-value", this, + "Add", "Can not be an indeterminate array."), 16081)); + } + + for (int i = 0; i < items.length; i++) + { + addSetElementImpl(pos + i, JsonBackend.instance().convertLegacyValueToJson(items[i]), true); + } + + return pos + items.length; + } + /** * Implements the {@code add} legacy methods for adding single element to this instance. * @@ -2912,7 +3133,7 @@ */ private void addElementImpl(BaseDataType element) { - addElementImpl(new integer(elements.size() + 1), element); + addElementImpl(new integer(elements.size()), element); } /** @@ -2925,7 +3146,16 @@ */ private void addElementImpl(integer idx, BaseDataType element) { - addSetElementImpl(idx, element, true); + int pos = idx == null || idx.isUnknown() ? -1 : idx.intValue(); + + // index zero means add it to the start + if (pos < 0 || pos > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("index", this, + "Add", "Can not be less than 0, UNKNOWN (?) or larger than the size of the array."), 16073)); + } + + addSetElementImpl(pos, element, true); } /** @@ -2938,51 +3168,68 @@ */ private void setElementImpl(integer idx, BaseDataType element) { - addSetElementImpl(idx, element, false); - } - - /** - * Implements the {@code add} and {@code set} legacy methods for adding single element to this instance. - * - * @param idx - * The 1-based array index where the element should be added. - * @param element - * The values to use as the initial json elements. - * @param add - * If set to {@code true} the method will implement semantics of {@code add} legacy methods. If - * {@code false} the method will implement semantics of the {@code set} legacy methods. - */ - private void addSetElementImpl(integer idx, BaseDataType element, boolean add) - { - if (idx == null || idx.isUnknown()) - { - returnError(ObjectOps.newInstance(JsonError.class)); - return; - } - - int i = idx.intValue() - 1; - int max = add ? elements.size() : elements.size() - 1; - if (i < 0 || i > max) - { - returnError(ObjectOps.newInstance(JsonError.class)); - return; - } - - try - { - addElement(idx.intValue(), JsonBackend.instance().convertLegacyValueToJson(element)); - if (add) - { - returnNormal(new integer(elements.size())); - } - else - { - returnNormal(new logical(true)); - } - } - catch (ClassCastException e) - { - returnError(ObjectOps.newInstance(JsonError.class)); + int pos = idx == null || idx.isUnknown() ? -1 : idx.intValue(); + + if (pos < 1 || pos > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("index", this, + "Set", "Can not be less than 1, UNKNOWN (?) or larger than the size of the array."), 16073)); + } + + addSetElementImpl(pos - 1, element, false); + } + + /** + * Implements the {@code add} and {@code set} legacy methods for adding single element to this instance. + * + * @param idx + * The 1-based array index where the element should be added. + * @param element + * The values to use as the initial json elements. + * @param add + * If set to {@code true} the method will implement semantics of {@code add} legacy methods. If + * {@code false} the method will implement semantics of the {@code set} legacy methods. + */ + private void addSetElementImpl(int idx, BaseDataType element, boolean add) + { + addSetElementImpl(idx, JsonBackend.instance().convertLegacyValueToJson(element), add); + + returnNormal(add ? new integer(idx + 1) : new logical(true)); + } + + /** + * Implements the {@code add} and {@code set} legacy methods for adding single element to this instance. + * + * @param idx + * The 1-based array index where the element should be added. + * @param element + * The values to use as the initial json elements. + * @param add + * If set to {@code true} the method will implement semantics of {@code add} legacy methods. If + * {@code false} the method will implement semantics of the {@code set} legacy methods. + */ + private void addSetElementImpl(int idx, Object element, boolean add) + { + + if (element != null && element instanceof JsonConstruct) + { + ObjectOps.increment((_BaseObject_) element); + } + + if (add) + { + if (idx > elements.size()) + { + elements.add(element); + } + else + { + elements.add(idx, element); + } + } + else + { + elements.set(idx, element); } } @@ -2996,76 +3243,7 @@ */ private void addElement(Object value) { - addElement(elements.size() + 1, value); - } - - /** - * Adds an element to the json array instance at the specified index. The supported types are - * {@linkplain JsonConstruct}, {@linkplain String}, {@linkplain Number}, {@linkplain Boolean}, or {@code - * null}. It is up to the caller to supply the correct type. - * - * @param idx - * The 1-based array index where the element should be added. - * @param value - * The value to add. - */ - private void addElement(int idx, Object value) - { - if (value instanceof JsonConstruct) - { - ObjectOps.increment((_BaseObject_) value); - } - - elements.add(idx - 1, value); - } - - /** - * Validates the supplied index. - * - * @param idx - * The index to validate. - * - * @return {@code true} if the index is valid, {@code false} otherwise. - */ - private boolean checkValidIndex(integer idx) - { - if (idx == null || idx.isUnknown()) - { - return false; - } - else - { - int i = idx.intValue() - 1; - return i >= 0 && i < elements.size(); - } - } - - /** - * Validates the supplied index and count. - * - * @param idx - * The index to validate. - * @param count - * Count value to validate. - * - * @return {@code true} if the index and count values are valid, {@code false} otherwise. - */ - private boolean checkValidIndexCount(integer idx, integer count) - { - if (!checkValidIndex(idx)) - { - return false; - } - - if (count == null || count.isUnknown()) - { - return false; - } - else - { - int cnt = count.intValue(); - return cnt >= 1 && idx.intValue() - 1 + cnt <= elements.size(); - } + addSetElementImpl(elements.size() + 1, value, true); } /** @@ -3080,46 +3258,43 @@ * corresponding legacy value. */ private void getElementImpl(integer idx, + String method, + int type, Function converter, Supplier nullSupplier) { - if (checkValidIndex(idx)) - { - Object val = elements.get(idx.intValue() - 1); - - BaseDataType res = null; - try - { - if (val == null) - { - res = nullSupplier.get(); - } - else - { - res = converter.apply(val); - } - } - catch(ClassCastException | DateTimeParseException ex) - { - log.log(Level.WARNING, "", ex); - // the value is not the expected type or has incorrect format - returnError(ObjectOps.newInstance(JsonError.class)); - } - catch(RuntimeException ex) - { - log.log(Level.WARNING, "", ex); - returnError(ObjectOps.newInstance(JsonError.class)); - } - - if (res != null) - { - returnNormal(res); - } - } - else - { + int pos = idx == null || idx.isUnknown() ? -1 : idx.intValue(); + + if (pos < 1 || pos > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("index", this, + method, "Can not be less than 1, UNKNOWN (?) or larger than the size of the array."), 16073)); + } + + Object val = elements.get(pos - 1); + int vtype = JsonBackend.instance().getJsonDataType(val); + + if (vtype == 6) + returnNormal(nullSupplier.get()); + + if (vtype != type) + { + undoThrow(JsonError.newInstance(String.format("Call to Progress.Json.ObjectModel.JsonArray:%s( ) failed. Expected a JSON %s value, found a JSON %s value.", + method, JsonBackend.instance().getJsonDataTypeName(type), JsonBackend.instance().getJsonDataTypeName(vtype)), 16060)); + } + + BaseDataType res = null; + try + { + res = converter.apply(val); + } + catch(Exception ex) + { + log.log(Level.WARNING, "", ex); returnError(ObjectOps.newInstance(JsonError.class)); } + + returnNormal(res); } /** @@ -3135,55 +3310,102 @@ * When the stored element is {@code null} this supplier will be used to retrieve the * corresponding legacy value. */ - private void getElementsImpl(integer idx, - integer count, - Function converter, - Supplier nullSupplier) - { - if (checkValidIndexCount(idx, count)) - { - BaseDataType[] res = new BaseDataType[count.intValue()]; - for (int i = idx.intValue() - 1; i < count.intValue(); i++) - { - Object val = elements.get(idx.intValue() - 1); - - try - { - if (val == null) - { - res[i] = nullSupplier.get(); - } - else - { - res[i] = converter.apply(val); - } - } - catch(ClassCastException | DateTimeParseException ex) - { - log.log(Level.WARNING, "", ex); - // the value is not the expected type or has incorrect format - returnError(ObjectOps.newInstance(JsonError.class)); - res = null; - break; - } - catch(RuntimeException ex) - { - log.log(Level.WARNING, "", ex); - returnError(ObjectOps.newInstance(JsonError.class)); - res = null; - break; - } - } - - if (res != null) - { - returnExtentNormal(res); - } - } - else - { - returnError(ObjectOps.newInstance(JsonError.class)); - } + private void getElementsImpl(integer idx, integer count, String method, int type, + Function converter, Supplier nullSupplier) + { + int pos = idx == null || idx.isUnknown() ? -1 : idx.intValue(); + int cnt = count == null || count.isUnknown() ? -1 : count.intValue(); + + if (pos < 1 || pos > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("index", this, + method, + "Can not be less than 1, UNKNOWN (?) or larger than the size of the array."), + 16073)); + } + + if (cnt < 1 || pos + cnt - 1 > elements.size()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("count", this, + method, + "Can not be less than 1, UNKNOWN (?) or larger than the size of the array."), + 16073)); + } + + BaseDataType[] res = new BaseDataType[cnt]; + for (int i = 0; i < cnt; i++) + { + Object val = elements.get(pos + i - 1); + + int vtype = JsonBackend.instance().getJsonDataType(val); + + if (vtype == 6) + res[i] = nullSupplier.get(); + + if (vtype != type) + { + undoThrow(JsonError.newInstance(String.format( + "Call to Progress.Json.ObjectModel.JsonArray:%s( ) failed. Expected a JSON %s value, found a JSON %s value.", + method, JsonBackend.instance().getJsonDataTypeName(type), + JsonBackend.instance().getJsonDataTypeName(vtype)), 16060)); + } + + res[i] = converter.apply(val); + + } + + returnExtentNormal(res); + + } + + @LegacySignature(type = Type.METHOD, name = "Read", parameters = + { + @LegacyParameter(name = "htt", type = "HANDLE", mode = "INPUT") + }) + public logical read(final handle htt) + { + return function(this, "Read", logical.class, new Block((Body) () -> { + returnNormal(read(htt, new logical(false))); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Read", parameters = + { + @LegacyParameter(name = "htt", type = "HANDLE", mode = "INPUT"), + @LegacyParameter(name = "omit", type = "LOGICAL", mode = "INPUT") + }) + public logical read(final handle _htt, final logical _omit) + { + handle htt = TypeFactory.initInput(_htt); + logical omit = TypeFactory.initInput(_omit); + + return function(this, "Read", logical.class, new Block((Body) () -> { + + if (!htt._isValid() || !CompareOps._isEqual(htt.unwrapType().getResourceType(), "temp-table")) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("temp-table handle", this, + "Read", "Not initialized or not a handle to a TEMP-TABLE."), 16070)); + } + + TempTable tmpTable = htt.unwrapTempTable(); + TemporaryBuffer tmpBuffer = (TemporaryBuffer) ((BufferReference) tmpTable.defaultBufferHandle().getResource()).buffer(); + + // remove current content + clear(); + + ObjectBuilder jb = new ObjectBuilder(this); + JsonExport export = new JsonExport(); + try + { + export.serializeTempTable(jb, tmpBuffer, !omit.isUnknown() && omit.booleanValue()); + returnNormal(new logical(true)); + } + catch (Exception e) + { + log.log(Level.WARNING, "", e); + returnError(ObjectOps.newInstance(JsonError.class)); + } + })); } } === modified file 'src/com/goldencode/p2j/oo/json/objectmodel/JsonConstruct.java' --- src/com/goldencode/p2j/oo/json/objectmodel/JsonConstruct.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/json/objectmodel/JsonConstruct.java 2021-01-29 09:04:34 +0000 @@ -19,6 +19,8 @@ ** 008 IAS 20190914 Fixed write(memptr) method. , ** 009 CA 20191024 Added method support levels and updated the class support level. ** 010 CA 20200503 Added stub for JsonConstruct:read(handle). +** 011 ME 20201028 Add routine level undo throw to avoid 'eating' errors. +** 20210128 Fix longchar to utf-8 for jsonText, 'null' string for nulls. */ /* @@ -81,6 +83,8 @@ import com.goldencode.p2j.persist.*; import com.goldencode.p2j.persist.serial.*; import com.goldencode.p2j.util.*; +import com.goldencode.p2j.util.BlockManager.Action; +import com.goldencode.p2j.util.BlockManager.Condition; import java.io.*; import java.nio.charset.*; @@ -111,8 +115,7 @@ { externalProcedure(JsonConstruct.this, new Block((Body) () -> { - { - } + onBlockLevel(Condition.ERROR, Action.THROW); })); } @@ -803,10 +806,31 @@ { ByteArrayOutputStream out = new ByteArrayOutputStream(); JsonBackend.instance().write(out, jsonConstruct, false, null); - String jsonString = out.toString("UTF-8"); - return new longchar(jsonString); + longchar ret = TypeFactory.longchar(); + ret.fixCodePage("UTF-8"); + ret.assign(out.toString("UTF-8")); + + return ret; } + protected longchar getJsonText(Object o) + throws IOException + { + if (o != null && o instanceof JsonConstruct) + { + return getJsonText((JsonConstruct) o); + } + else + { + longchar ret = TypeFactory.longchar(); + ret.fixCodePage("UTF-8"); + + ret.assign(o == null ? "null" : o.toString()); + + return ret; + } + } + /** * Implements the method {@link #read(TableParameter)} and {@link #read(TableParameter, logical)} for * json object and array classes. === modified file 'src/com/goldencode/p2j/oo/json/objectmodel/JsonObject.java' --- src/com/goldencode/p2j/oo/json/objectmodel/JsonObject.java 2019-11-14 17:48:22 +0000 +++ src/com/goldencode/p2j/oo/json/objectmodel/JsonObject.java 2021-01-30 11:30:03 +0000 @@ -680,7 +680,7 @@ { try { - return getJsonText((JsonConstruct) o); + return getJsonText(o); } catch (IOException e) { === modified file 'src/com/goldencode/p2j/oo/json/objectmodel/ObjectModelParser.java' --- src/com/goldencode/p2j/oo/json/objectmodel/ObjectModelParser.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/json/objectmodel/ObjectModelParser.java 2021-01-18 12:12:45 +0000 @@ -10,6 +10,7 @@ ** 003 CA 20190423 Added LegacyResource annotation. ** 004 HC 20190701 Implemented most of the legacy methods. ** 005 CA 20191024 Added method support levels and updated the class support level. +** 006 ME 20210115 Fix (some of) the error handling to match the 4GL side. */ /* @@ -69,7 +70,7 @@ import java.io.*; -import com.goldencode.p2j.*; +import com.fasterxml.jackson.core.JsonParseException; import com.goldencode.p2j.util.*; import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; @@ -78,12 +79,13 @@ import static com.goldencode.p2j.util.BlockManager.*; import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.InternalEntry.Type; +import static com.goldencode.p2j.util.TextOps.substitute; /** * Implementation of the Progress.Json.Objectmodel.ObjectModelParser builtin class. */ @LegacyResource(resource = "Progress.Json.Objectmodel.ObjectModelParser") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_BASIC) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class ObjectModelParser extends com.goldencode.p2j.oo.json.JsonParser { @@ -127,21 +129,33 @@ { @LegacyParameter(name = "str", type = "HANDLE", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_BASIC) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public object parse(final handle _str) { handle str = TypeFactory.initInput(_str); return function(this, "Parse", object.class, new Block((Body) () -> { - if (str == null || str.isUnknown()) + // TODO: wrap that to WEB-CONTEXT handle when available, only accepted input value + if (str == null || str.isUnknown() || !LegacyResource.PSEUDO_WIDGET.equals(str.unwrapType().getResourceType().getValue())) { - // TODO: make this compatible with the 4GL - returnError(ObjectOps.newInstance(JsonError.class)); + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("source", this, + "Parse", "Must be a WEB-CONTEXT handle."), 16071)); } - Stream s = (Stream) str.getResource(); - returnNormal(JsonBackend.instance().parse(new InputStreamWrapper(s))); + object res = TypeFactory.object(JsonConstruct.class); + + try (InputStream is = new InputStreamWrapper((Stream) str.getResource())) + { + res.assign(JsonBackend.instance().parse(is)); + is.close(); + } + catch (Exception exc) + { + handleError(exc); + } + + returnNormal(res); })); } @@ -154,26 +168,49 @@ * * @return The top level JSON construct. */ - @LegacySignature(type = Type.METHOD, name = "Parse", qualified = "Progress.Json.ObjectModel.JsonConstruct", parameters = - { - @LegacyParameter(name = "source", type = "LONGCHAR", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_BASIC) + @LegacySignature(type = Type.METHOD, name = "Parse", qualified = "Progress.Json.ObjectModel.JsonConstruct", parameters = { + @LegacyParameter(name = "source", type = "LONGCHAR", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object parse(final longchar _source) { longchar source = TypeFactory.initInput(_source); - - return function(this, "Parse", object.class, new Block((Body) () -> - { - if (source == null || source.isUnknown()) + + return function(this, "Parse", object.class, new Block((Body) () -> { + // only if unknown or empty space, spaces only are (attempted to be) parsed + if (source == null || source.isUnknown() || source.getValue().isEmpty()) { - // TODO: make this compatible with the 4GL - ErrorManager.recordOrThrowError(-1, "Can't read from invalid longchar instance."); - returnError(ObjectOps.newInstance(JsonParserError.class)); + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("source", this, + "Parse", "Can not be UNKNOWN (?) or empty string."), 16055)); } + + String cp = source._getCodePage().toLowerCase(); - String input = source.toStringMessage(); - returnNormal(JsonBackend.instance().parse(input)); + if (!cp.startsWith("utf")) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("encoding", this, + "Parse", String.format("'%s' is not a valid UTF encoding.", source._getCodePage())), 16063)); + } + + if (!cp.equals("utf-8")) + { + longchar utf8Source = I18nOps.codePageConvert(source, "utf-8", cp); + returnNormal(parse(utf8Source)); + } + else + { + object res = TypeFactory.object(JsonConstruct.class); + + try + { + res.assign(JsonBackend.instance().parse(source.getValue())); + } + catch (Exception exc) + { + handleError(exc); + } + + returnNormal(res); + } })); } @@ -190,23 +227,32 @@ { @LegacyParameter(name = "source", type = "MEMPTR", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_BASIC) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public object parse(final memptr _source) { memptr source = TypeFactory.initInput(_source); return function(this, "Parse", object.class, new Block((Body) () -> { - if (source == null || source.isUnknown()) - { - // TODO: make this compatible with the 4GL - ErrorManager.recordOrThrowError(-1, "Can't read from invalid memptr instance."); - returnError(ObjectOps.newInstance(JsonParserError.class)); - } - - character text = source.getString(1); - String input = text.isUnknown() ? "" : text.toStringMessage(); - returnNormal(JsonBackend.instance().parse(input)); + if (source == null || source.isUnknown() || source.isUninitialized()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("source", this, + "Parse", "Can not be UNKNOWN (?) or empty string."), 16055)); + } + + // empty string does not throw as for character/longchar so parse the string directly + object res = TypeFactory.object(JsonConstruct.class); + + try + { + res.assign(JsonBackend.instance().parse(source.getString(1).toStringMessage())); + } + catch (Exception exc) + { + handleError(exc); + } + + returnNormal(res); })); } @@ -223,22 +269,32 @@ { @LegacyParameter(name = "source", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_BASIC) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public object parse(final character _source) { character source = TypeFactory.initInput(_source); return function(this, "Parse", object.class, new Block((Body) () -> { - if (source == null || source.isUnknown()) - { - // TODO: make this compatible with the 4GL - ErrorManager.recordOrThrowError(-1, "Can't read from invalid character instance."); - returnError(ObjectOps.newInstance(JsonParserError.class)); - } - - String input = source.toStringMessage(); - returnNormal(JsonBackend.instance().parse(input)); + // only if unknown or empty space, spaces only are (attempted to be) parsed + if (source == null || source.isUnknown() || source.getValue().isEmpty()) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("source", this, + "Parse", "Can not be UNKNOWN (?) or empty string."), 16055)); + } + + object res = TypeFactory.object(JsonConstruct.class); + + try + { + res.assign(JsonBackend.instance().parse(source.toStringMessage())); + } + catch (Exception exc) + { + handleError(exc); + } + + returnNormal(res); })); } @@ -255,43 +311,59 @@ { @LegacyParameter(name = "fname", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_BASIC) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public object parseFile(final character _fname) { character fname = TypeFactory.initInput(_fname); return function(this, "ParseFile", object.class, new Block((Body) () -> { - if (fname == null || fname.isUnknown()) + if (TextOps.isEmpty(fname)) { - // TODO: make this compatible with the 4GL - ErrorManager.recordOrThrowError(-1, "Can't read from invalid filename."); - returnError(ObjectOps.newInstance(JsonParserError.class)); + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("source", this, + "ParseFile", "Can not be UNKNOWN (?) or empty string."), 16055)); } String filename = fname.toStringMessage(); Stream stream = StreamFactory.openFileStream(filename, false, false); - if (stream == null) - { - // TODO: make this compatible with the 4GL - ErrorManager.recordOrThrowError(-1, "Can't open filename " + filename); - returnError(ObjectOps.newInstance(JsonParserError.class)); - } + object res = TypeFactory.object(JsonConstruct.class); // this reads the client-side file try (InputStream is = new InputStreamWrapper(stream)) { - object res = TypeFactory.object(JsonConstruct.class); res.assign(JsonBackend.instance().parse(is)); - returnNormal(res); + is.close(); } - catch (IOException exc) + catch (Exception exc) { - // TODO: make this compatible with the 4GL - ErrorManager.recordOrThrowError(-1, "I/O failure.", new NumberedException(exc)); - returnError(ObjectOps.newInstance(JsonParserError.class)); - } + handleError(exc); + } + finally { + stream.close(); + } + + returnNormal(res); })); } + + private void handleError (Exception exc) { + if (exc.getCause() != null && exc.getCause() instanceof CharConversionException) + { + // offset seems to always be 1 + undoThrow(JsonParserError.newInstance("Json Parser Error at offset 1: lexical error: invalid char in json text..", 16068)); + } + else if (exc instanceof JsonParseException) + { + // TODO: align the message details with 4GL + undoThrow(JsonParserError.newInstance(substitute("Json Parser Error at offset &1: parse error: &2", + ((JsonParseException) exc).getLocation().getByteOffset(), + exc.getMessage()).getValue(), 16068)); + } + else + { + undoThrow(JsonParserError.newInstance(substitute("Json Parser Error: unknown error: &2", + exc.getMessage()).getValue(), 16068)); + } + } } === modified file 'src/com/goldencode/p2j/oo/lang/BaseObject.java' --- src/com/goldencode/p2j/oo/lang/BaseObject.java 2020-06-05 18:02:00 +0000 +++ src/com/goldencode/p2j/oo/lang/BaseObject.java 2021-01-15 07:19:19 +0000 @@ -16,6 +16,7 @@ ** 007 CA 20200330 Fixed legacy ToString method. ** GES 20200520 Minor NPE protection added. ** GES 20200603 Moved class registration into a static initializer. +** 008 ME 20210115 Override equals using legacyEquals and hashCode to use resource id (if possible). */ /* @@ -218,8 +219,8 @@ @Override public object clone() { - ErrorManager.recordOrShowError(13444, "Clone method is undefined for the class", - true, false, false); + ErrorManager.recordOrThrowError(13444, "Clone method is undefined for the class", + false, false); return new object<>(); } @@ -232,4 +233,25 @@ { Assert.notNull(str, new character(name)); } + + @Override + public int hashCode() + { + return handle.resourceId(ObjectOps.asResource(this)).intValue(); + } + + @Override + public boolean equals(Object obj) + { + if (obj != null) { + if (obj instanceof object) + return legacyEquals((object) obj).booleanValue(); + if (obj instanceof _BaseObject_) + return legacyEquals(new object((_BaseObject_) obj)).booleanValue(); + } + + return super.equals(obj); + } + + } === modified file 'src/com/goldencode/p2j/oo/lang/LegacyClass.java' --- src/com/goldencode/p2j/oo/lang/LegacyClass.java 2020-06-05 18:02:00 +0000 +++ src/com/goldencode/p2j/oo/lang/LegacyClass.java 2020-10-23 12:54:30 +0000 @@ -77,6 +77,7 @@ package com.goldencode.p2j.oo.lang; +import java.io.Serializable; import java.lang.reflect.*; import com.goldencode.p2j.oo.reflect.LegacyConstructor; @@ -242,6 +243,14 @@ return getLegacyClass(typeName.isUnknown() ? "" : typeName.toStringMessage()); } + public static object getLegacyClass(object obj) + { + if (obj == null || !obj._isValid()) + return null; + + return LegacyClass.class.equals(obj.ref().getClass()) ? (object) obj : obj.ref().getLegacyClass(); + } + /** * Resolve the legacy class from the given name. * @@ -519,7 +528,8 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public logical isFinal() { - return new logical(Modifier.isFinal(cls.getModifiers())); + // SysError can be extended in application although is the super class of other 4GL errors + return new logical(SysError.class.equals(cls) || Modifier.isFinal(cls.getModifiers())); } @LegacySignature(type = Type.METHOD, name = "IsGeneric") @@ -539,7 +549,9 @@ @LegacySignature(type = Type.METHOD, name = "IsSerializable") public logical isSerializable() { - return function(LegacyClass.class, this, "IsSerializable", logical.class, new Block()); + // TODO: 4GL serialization does not use an interface, some annotation maybe + // a class can be non-serializable even if it's base class is + return new logical(cls.isAssignableFrom(Serializable.class)); } /** === modified file 'src/com/goldencode/p2j/oo/lang/OerequestInfo.java' --- src/com/goldencode/p2j/oo/lang/OerequestInfo.java 2020-05-28 18:51:24 +0000 +++ src/com/goldencode/p2j/oo/lang/OerequestInfo.java 2020-10-23 12:54:30 +0000 @@ -79,7 +79,7 @@ */ @LegacyResource(resource = "Progress.Lang.OERequestInfo") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) -public class OerequestInfo +public final class OerequestInfo extends BaseObject { /** === modified file 'src/com/goldencode/p2j/oo/lang/OeversionInfo.java' --- src/com/goldencode/p2j/oo/lang/OeversionInfo.java 2020-04-27 16:17:03 +0000 +++ src/com/goldencode/p2j/oo/lang/OeversionInfo.java 2020-10-23 12:54:30 +0000 @@ -81,7 +81,7 @@ */ @LegacyResource(resource = "Progress.Lang.OEVersionInfo") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) -public class OeversionInfo +public final class OeversionInfo extends BaseObject { /** Only "4GLCLIENT" and "APPSERVER" types are supported at this time. */ === modified file 'src/com/goldencode/p2j/oo/lang/ParameterList.java' --- src/com/goldencode/p2j/oo/lang/ParameterList.java 2021-01-13 12:02:59 +0000 +++ src/com/goldencode/p2j/oo/lang/ParameterList.java 2021-01-31 10:14:52 +0000 @@ -81,7 +81,7 @@ */ @LegacyResource(resource = "Progress.Lang.ParameterList") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_BASIC) -public class ParameterList +public final class ParameterList extends BaseObject { @@ -174,9 +174,9 @@ if (num.isUnknown() || num.intValue() < 0) { - undoThrow(SysError.newInstance("The argument to the ParameterList Constructor, and " + + ErrorManager.recordOrThrowError(15672, "The argument to the ParameterList Constructor, and " + "the value for ParameterList:NumParameters, must be a " + - "valid non-negative integer", 15672)); + "valid non-negative integer", false); } this.parameters = new CallParameter[num.intValue()]; @@ -225,14 +225,12 @@ if (pos.isUnknown() || pos.intValue() < 0 || pos.intValue() > this.getNumParameters().intValue()) { String msg = "SetParameter position must be 1 based and less than or equal to " + this.getNumParameters().intValue() + "."; - undoThrow(SysError.newInstance(msg, 15293)); - return new logical(false); + ErrorManager.recordOrThrowError(15293, msg, false); } if (type.isUnknown()) { - undoThrow(SysError.newInstance("Unusable datatype for SetParameter method.", 15295)); - return new logical(false); + ErrorManager.recordOrThrowError(15295, "Unusable datatype for SetParameter method.", false); } CallMode cmode = CallMode.buildMode(mode); @@ -241,8 +239,7 @@ String msg = "SetParameter IOmode parameter is required in the overload" + " being used, and should be 'INPUT', 'OUTPUT', 'INPUT-OUTPUT'" + " and so on."; - undoThrow(SysError.newInstance(msg, 15297)); - return new logical(false); + ErrorManager.recordOrThrowError(15297, msg, false); } if (!cmode.input && !Call.validOutputParameter(pos.intValue(), val)) @@ -250,7 +247,7 @@ return new logical(false); } - CallParameter param = Call.createParameter(type.getValue(), cmode, val, null); + CallParameter param = Call.createParameter(type.getValue(), cmode, val, false, true); if (param == null) { === modified file 'src/com/goldencode/p2j/oo/lang/SysError.java' --- src/com/goldencode/p2j/oo/lang/SysError.java 2020-04-23 06:31:53 +0000 +++ src/com/goldencode/p2j/oo/lang/SysError.java 2021-01-15 11:17:07 +0000 @@ -10,6 +10,7 @@ ** 003 CA 20191024 Added method support levels and updated the class support level. ** 004 CA 20200330 Added constructor to build a new error with message and number and APIs to ** create new instances. +** ME 20210111 Fix method signature for new instances static APIs. */ /* @@ -127,7 +128,6 @@ integer num = TypeFactory.initInput(_num); internalProcedure(this, "__lang_SysError_constructor__", new Block((Body) () -> { - msg.assign(ErrorManager.buildErrorText(num.intValue(), msg.getValue(), false, false)); __lang_ProError_constructor__(msg, num); })); } @@ -140,7 +140,7 @@ * @param num * The error number. */ - public static object newInstance(character msg, integer num) + public static object newInstance(character msg, integer num) { return ObjectOps.newInstance(SysError.class, "II", msg, num); } @@ -153,8 +153,9 @@ * @param num * The error number. */ - public static object newInstance(String msg, int num) + public static object newInstance(String msg, int num) { return ObjectOps.newInstance(SysError.class, "II", msg, num); } + } === modified file 'src/com/goldencode/p2j/oo/logging/LogLevelEnum.java' --- src/com/goldencode/p2j/oo/logging/LogLevelEnum.java 2020-04-29 15:30:25 +0000 +++ src/com/goldencode/p2j/oo/logging/LogLevelEnum.java 2020-12-07 13:46:45 +0000 @@ -10,6 +10,7 @@ ** 002 CA 20191024 Added method support levels and updated the class support level. ** 003 ME 20200415 Implement missing enums. ** 004 GES 20200429 Shifted to new legacy enum approach. +** 005 ME 20201207 Fix enums to lower case to follow conversion convention. */ /* @@ -67,50 +68,59 @@ package com.goldencode.p2j.oo.logging; -import com.goldencode.p2j.util.*; -import com.goldencode.p2j.oo.lang.*; -import com.goldencode.p2j.oo.net.UriEncodingTypeEnum; -import com.goldencode.p2j.security.ContextLocal; - -import static com.goldencode.p2j.util.BlockManager.*; -import static com.goldencode.p2j.report.ReportConstants.*; -import static com.goldencode.p2j.util.InternalEntry.Type; - -import java.util.ArrayList; +import static com.goldencode.p2j.report.ReportConstants.CVT_LVL_FULL; +import static com.goldencode.p2j.report.ReportConstants.RT_LVL_FULL; + +import com.goldencode.p2j.oo.lang.LegacyEnum; +import com.goldencode.p2j.util.InternalEntry.Type; +import com.goldencode.p2j.util.LegacyParameter; +import com.goldencode.p2j.util.LegacyResource; +import com.goldencode.p2j.util.LegacyResourceSupport; +import com.goldencode.p2j.util.LegacySignature; +import com.goldencode.p2j.util.character; +import com.goldencode.p2j.util.int64; +import com.goldencode.p2j.util.object; /** * Replacement class for OpenEdge.Logging.LogLevelEnum. */ @LegacyResource(resource = "OpenEdge.Logging.LogLevelEnum") -@LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL|RT_LVL_STUB) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class LogLevelEnum extends LegacyEnum { - public static final object OFF; - - public static final object FATAL; - - public static final object ERROR; - - public static final object WARN; - - public static final object INFO; - - public static final object DEBUG; - - public static final object TRACE; + @LegacySignature(type = Type.VARIABLE, name = "OFF") + public static final object off; + + @LegacySignature(type = Type.VARIABLE, name = "FATAL") + public static final object fatal; + + @LegacySignature(type = Type.VARIABLE, name = "ERROR") + public static final object error; + + @LegacySignature(type = Type.VARIABLE, name = "WARN") + public static final object warn; + + @LegacySignature(type = Type.VARIABLE, name = "INFO") + public static final object info; + + @LegacySignature(type = Type.VARIABLE, name = "DEBUG") + public static final object debug; + + @LegacySignature(type = Type.VARIABLE, name = "TRACE") + public static final object trace; static { registerEnum(LogLevelEnum.class, LogLevelEnum::new, "OpenEdge.Logging.LogLevelEnum"); - OFF = createEnum(LogLevelEnum.class, "OFF", 0); - FATAL = createEnum(LogLevelEnum.class, "FATAL"); - ERROR = createEnum(LogLevelEnum.class, "ERROR"); - WARN = createEnum(LogLevelEnum.class, "WARN"); - INFO = createEnum(LogLevelEnum.class, "INFO"); - DEBUG = createEnum(LogLevelEnum.class, "DEBUG"); - TRACE = createEnum(LogLevelEnum.class, "TRACE"); + off = createEnum(LogLevelEnum.class, "OFF", 0); + fatal = createEnum(LogLevelEnum.class, "FATAL"); + error = createEnum(LogLevelEnum.class, "ERROR"); + warn = createEnum(LogLevelEnum.class, "WARN"); + info = createEnum(LogLevelEnum.class, "INFO"); + debug = createEnum(LogLevelEnum.class, "DEBUG"); + trace = createEnum(LogLevelEnum.class, "TRACE"); } private LogLevelEnum(String name, Long value) === modified file 'src/com/goldencode/p2j/oo/net/MediaLinkEntity.java' --- src/com/goldencode/p2j/oo/net/MediaLinkEntity.java 2020-06-15 00:40:59 +0000 +++ src/com/goldencode/p2j/oo/net/MediaLinkEntity.java 2020-11-27 06:51:28 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 MP 20200602 First version, stubs taken by converting the skeleton using FWD. +** 002 ME 20201126 Implement all methods as per OE12.2. ** */ @@ -67,11 +68,15 @@ import com.goldencode.p2j.util.*; import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; +import com.goldencode.p2j.oo.core.Assert; +import com.goldencode.p2j.oo.core.SerializationFormatEnum; +import com.goldencode.p2j.oo.json.objectmodel.JsonObject; +import com.goldencode.p2j.oo.json.objectmodel.ObjectModelParser; import com.goldencode.p2j.oo.lang.*; -import static com.goldencode.p2j.report.ReportConstants.CVT_LVL_FULL; -import static com.goldencode.p2j.report.ReportConstants.RT_LVL_STUB; +import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.*; +import static com.goldencode.p2j.util.CompareOps._isEqual; import static com.goldencode.p2j.util.InternalEntry.Type; /** @@ -79,20 +84,20 @@ * in OpenEdge/Net/MediaLinkEntity.cls). */ @LegacyResource(resource = "OpenEdge.Net.MediaLinkEntity") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class MediaLinkEntity extends BaseObject { @LegacySignature(type = Type.PROPERTY, name = "ReadUrl") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) private character readUrl = TypeFactory.character(); @LegacySignature(type = Type.PROPERTY, name = "EditUrl") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) private character editUrl = TypeFactory.character(); @LegacySignature(type = Type.PROPERTY, name = "ResourceName") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) private character resourceName = TypeFactory.character(); public void __net_MediaLinkEntity_execute__() @@ -100,13 +105,11 @@ externalProcedure(MediaLinkEntity.class, MediaLinkEntity.this, new Block((Body) () -> { onBlockLevel(Condition.ERROR, Action.THROW); - { - } })); } @LegacySignature(type = Type.GETTER, name = "ReadUrl") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public character getReadUrl() { return function(MediaLinkEntity.class, this, "ReadUrl", character.class, new Block((Body) () -> @@ -119,19 +122,21 @@ { @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void setReadUrl(final character _var) { character var = TypeFactory.initInput(_var); internalProcedure(MediaLinkEntity.class, this, "ReadUrl", new Block((Body) () -> { + Assert.notNull(var, new character("Media resource read URL")); + readUrl.assign(var); })); } @LegacySignature(type = Type.GETTER, name = "EditUrl") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public character getEditUrl() { return function(MediaLinkEntity.class, this, "EditUrl", character.class, new Block((Body) () -> @@ -144,19 +149,21 @@ { @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void setEditUrl(final character _var) { character var = TypeFactory.initInput(_var); internalProcedure(MediaLinkEntity.class, this, "EditUrl", new Block((Body) () -> { + Assert.notNull(var, new character("Media resource edit URL")); + editUrl.assign(var); })); } @LegacySignature(type = Type.GETTER, name = "ResourceName") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public character getResourceName() { return function(MediaLinkEntity.class, this, "ResourceName", character.class, new Block((Body) () -> @@ -169,13 +176,15 @@ { @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void setResourceName(final character _var) { character var = TypeFactory.initInput(_var); internalProcedure(MediaLinkEntity.class, this, "ResourceName", new Block((Body) () -> { + Assert.notNull(var, new character("Media resource name")); + resourceName.assign(var); })); } @@ -184,14 +193,13 @@ { @LegacyParameter(name = "pcReadUrl", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_MediaLinkEntity_constructor__(final character _pcReadUrl) { - character pcReadUrl = TypeFactory.initInput(_pcReadUrl); - internalProcedure(MediaLinkEntity.class, this, "__net_MediaLinkEntity_constructor__", new Block((Body) () -> { __lang_BaseObject_constructor__(); + setReadUrl(_pcReadUrl); })); } @@ -200,15 +208,13 @@ @LegacyParameter(name = "pcReadUrl", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "pcEditUrl", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_MediaLinkEntity_constructor__(final character _pcReadUrl, final character _pcEditUrl) { - character pcReadUrl = TypeFactory.initInput(_pcReadUrl); - character pcEditUrl = TypeFactory.initInput(_pcEditUrl); - internalProcedure(MediaLinkEntity.class, this, "__net_MediaLinkEntity_constructor__", new Block((Body) () -> { - __lang_BaseObject_constructor__(); + __net_MediaLinkEntity_constructor__(_pcReadUrl); + setEditUrl(_pcEditUrl); })); } @@ -216,18 +222,16 @@ { @LegacyParameter(name = "poReadUrl", type = "OBJECT", qualified = "openedge.net.uri", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_MediaLinkEntity_constructor__(final object _poReadUrl) { object poReadUrl = TypeFactory.initInput(_poReadUrl); - internalProcedure(MediaLinkEntity.class, this, "__net_MediaLinkEntity_constructor__", new Block((Init) () -> - { - ObjectOps.register(poReadUrl); - }, - (Body) () -> - { - __lang_BaseObject_constructor__(); + internalProcedure(MediaLinkEntity.class, this, "__net_MediaLinkEntity_constructor__", new Block((Body) () -> + { + Assert.notNull(poReadUrl, new character("Read URI")); + + __net_MediaLinkEntity_constructor__(poReadUrl.ref().toLegacyString()); })); } @@ -236,24 +240,23 @@ @LegacyParameter(name = "poReadUrl", type = "OBJECT", qualified = "openedge.net.uri", mode = "INPUT"), @LegacyParameter(name = "poEditUrl", type = "OBJECT", qualified = "openedge.net.uri", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_MediaLinkEntity_constructor__(final object _poReadUrl, final object _poEditUrl) { object poReadUrl = TypeFactory.initInput(_poReadUrl); object poEditUrl = TypeFactory.initInput(_poEditUrl); - internalProcedure(MediaLinkEntity.class, this, "__net_MediaLinkEntity_constructor__", new Block((Init) () -> - { - ObjectOps.register(poEditUrl, poReadUrl); - }, - (Body) () -> - { - __lang_BaseObject_constructor__(); + internalProcedure(MediaLinkEntity.class, this, "__net_MediaLinkEntity_constructor__", new Block((Body) () -> + { + Assert.notNull(poReadUrl, new character("Read URI")); + Assert.notNull(poEditUrl, new character("Edit URI")); + + __net_MediaLinkEntity_constructor__(poReadUrl.ref().toLegacyString(), poEditUrl.ref().toLegacyString()); })); } @LegacySignature(type = Type.CONSTRUCTOR) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_MediaLinkEntity_constructor__() { internalProcedure(MediaLinkEntity.class, this, "__net_MediaLinkEntity_constructor__", new Block((Body) () -> @@ -262,12 +265,22 @@ })); } + @LegacySignature(type = Type.CONSTRUCTOR) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public static void __net_MediaLinkEntity_constructor__static__() + { + externalProcedure(MediaLinkEntity.class, new Block((Body) () -> + { + onBlockLevel(Condition.ERROR, Action.THROW); + })); + } + @LegacySignature(type = Type.METHOD, name = "Deserialize", qualified = "openedge.net.medialinkentity", parameters = { @LegacyParameter(name = "pcMLE", type = "LONGCHAR", mode = "INPUT"), @LegacyParameter(name = "poSerializedAs", type = "OBJECT", qualified = "openedge.core.serializationformatenum", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static object deserialize(final longchar _pcMle, final object _poSerializedAs) { longchar pcMle = TypeFactory.initInput(_pcMle); @@ -275,22 +288,106 @@ return function(MediaLinkEntity.class, "Deserialize", object.class, new Block((Body) () -> { - UnimplementedFeature.missing("MediaLinkEntity:Deserialize METHOD"); - })); - } - - @LegacySignature(type = Type.METHOD, name = "Serialize", parameters = - { - @LegacyParameter(name = "poSerializedAs", type = "OBJECT", qualified = "openedge.core.serializationformatenum", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public longchar serialize(final object _poSerializedAs) - { - object poSerializedAs = TypeFactory.initInput(_poSerializedAs); - - return function(MediaLinkEntity.class, this, "Serialize", longchar.class, new Block((Body) () -> - { - UnimplementedFeature.missing("MediaLinkEntity:Serialize METHOD"); - })); - } + Assert.notNull(poSerializedAs, new character("MLE serialization type")); + Assert.notNullOrEmpty(pcMle, new character("Serialized MLE")); + + if (!_isEqual(poSerializedAs, SerializationFormatEnum.json) + && !_isEqual(poSerializedAs, SerializationFormatEnum.quotedJson)) + { + undoThrow(AppError.newInstance( + TextOps.substitute("Unsupported MLE serialization type &1", + poSerializedAs), + new integer(0))); + } + + object mle = ObjectOps.newInstance(MediaLinkEntity.class); + + object parser = ObjectOps.newInstance(ObjectModelParser.class); + object jsonObj = ObjectOps.cast(parser.ref().parse(pcMle), JsonObject.class); + + character prop = new character("src"); + + if (jsonObj.ref().has(prop).booleanValue()) + { + mle.ref().setReadUrl(jsonObj.ref().getCharacter(prop)); + + prop.assign("name"); + + if (jsonObj.ref().has(prop).booleanValue()) + { + mle.ref().setResourceName(jsonObj.ref().getCharacter(prop)); + } + } + + prop.assign("edit-media"); + + if (jsonObj.ref().has(prop).booleanValue()) + { + mle.ref().setEditUrl(jsonObj.ref().getCharacter(prop)); + } + + returnNormal(mle); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Serialize", parameters = { + @LegacyParameter(name = "poSerializedAs", type = "OBJECT", qualified = "openedge.core.serializationformatenum", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public longchar serialize( + final object _poSerializedAs) + { + object poSerializedAs = TypeFactory + .initInput(_poSerializedAs); + + return function(MediaLinkEntity.class, this, "Serialize", longchar.class, + new Block((Body) () -> { + Assert.notNull(poSerializedAs, new character("MLE serialization type")); + + if (TextOps.isEmpty(readUrl) && TextOps.isEmpty(editUrl)) + { + undoThrow(AppError + .newInstance("Either a ReadUrl or EditUrl must be specified", 0)); + } + + if (!_isEqual(poSerializedAs, SerializationFormatEnum.json) + && !_isEqual(poSerializedAs, SerializationFormatEnum.quotedJson)) + { + undoThrow(AppError.newInstance( + TextOps.substitute("Unsupported MLE serialization type &1", + poSerializedAs), + new integer(0))); + } + + object jsonObj = ObjectOps.newInstance(JsonObject.class); + + if (!TextOps.isEmpty(readUrl)) + { + jsonObj.ref().add(new character("src"), readUrl); + + if (!TextOps.isEmpty(resourceName)) + { + jsonObj.ref().add(new character("name"), resourceName); + } + } + + if (!TextOps.isEmpty(editUrl)) + { + jsonObj.ref().add(new character("edit-media"), editUrl); + } + + longchar payload = TypeFactory.longchar(); + + payload.fixCodePage("utf-8"); + payload.assign(jsonObj.ref().getJsonText()); + + if (_isEqual(poSerializedAs, SerializationFormatEnum.quotedJson)) + { + payload.assign(character.quoter(payload)); + } + + returnNormal(payload); + + })); + } + } === modified file 'src/com/goldencode/p2j/oo/net/MessagePart.java' --- src/com/goldencode/p2j/oo/net/MessagePart.java 2020-04-15 21:31:52 +0000 +++ src/com/goldencode/p2j/oo/net/MessagePart.java 2020-11-25 12:26:57 +0000 @@ -9,6 +9,7 @@ ** 002 IAS 20190527 Added multipart support. ** 003 CA 20191024 Added method support levels and updated the class support level. ** 004 ME 20200413 Clean-up and fix toString legacy method. +** 20201125 Set header value 'fluent', use substitute for toString. */ /* @@ -82,7 +83,7 @@ * in OpenEdge/Net/MessagePart.cls). */ @LegacyResource(resource = "OpenEdge.Net.MessagePart") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_PARTIAL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class MessagePart extends BaseObject { @@ -256,8 +257,7 @@ else { object hdr = TypeFactory.object(HttpHeader.class); - hdr.assign(HttpHeaderBuilder.build(hdrn).ref().getHeader()); - hdr.ref().setValue(var); + hdr.assign(HttpHeaderBuilder.build(hdrn).ref().value(var).ref().getHeader()); headers.ref().put(hdr); } })); @@ -373,18 +373,7 @@ { return function(this, "ToString", character.class, new Block((Body) () -> { - String sRsp = getContentType().getValue() + "_"; - - if (!body.isUnknown()) - { - sRsp += body.ref().toLegacyString(); - } - else - { - sRsp += object.resourceId(new object<>(this)); - } - - returnNormal(new character(sRsp)); + returnNormal(TextOps.substitute("&1_&2", getContentType(), handle.resourceId(ObjectOps.asResource(this)))); } )); } === modified file 'src/com/goldencode/p2j/oo/net/MimeTypeHelper.java' --- src/com/goldencode/p2j/oo/net/MimeTypeHelper.java 2020-04-15 21:24:43 +0000 +++ src/com/goldencode/p2j/oo/net/MimeTypeHelper.java 2020-10-19 07:49:54 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 MP 20200401 First version, stubs taken by converting the skeleton using FWD. +** 002 ME 20201019 Remove dependency to StringUtils. */ /* @@ -73,8 +74,6 @@ import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.InternalEntry.Type; -import org.apache.commons.lang.StringUtils; - /** * Business logic (converted to Java from the 4GL source code * in OpenEdge/Net/MessagePart.cls). @@ -170,7 +169,7 @@ return function(MimeTypeHelper.class, "IsFormEncoded", logical.class, new Block((Body) () -> { - if (p1.isUnknown() || StringUtils.isBlank(p1.getValue())) + if (p1.isUnknown() || TextOps.isEmpty(p1.getValue())) { returnNormal(new logical(false)); } @@ -182,10 +181,10 @@ returnNormal(new logical(false)); } - returnNormal(new logical((entries[0].toLowerCase().equals("application") - && entries[1].toLowerCase().equals("x-www-form-urlencoded")) - || (entries[0].toLowerCase().equals("multipart") - && entries[1].toLowerCase().equals("form-data")))); + returnNormal(new logical((entries[0].equalsIgnoreCase("application") + && entries[1].equalsIgnoreCase("x-www-form-urlencoded")) + || (entries[0].equalsIgnoreCase("multipart") + && entries[1].equalsIgnoreCase("form-data")))); })); } @@ -206,7 +205,7 @@ return function(MimeTypeHelper.class, "IsMultipart", logical.class, new Block((Body) () -> { - if (p1.isUnknown() || StringUtils.isBlank(p1.getValue())) + if (p1.isUnknown() || TextOps.isEmpty(p1.getValue())) { returnNormal(new logical(false)); } @@ -218,7 +217,7 @@ returnNormal(new logical(false)); } - returnNormal(new logical(entries[0].toLowerCase().equals("multipart"))); + returnNormal(new logical(entries[0].equalsIgnoreCase("multipart"))); })); } @@ -238,7 +237,7 @@ return function(MimeTypeHelper.class, "IsJson", logical.class, new Block((Body) () -> { - if (p1.isUnknown() || StringUtils.isBlank(p1.getValue())) + if (p1.isUnknown() || TextOps.isEmpty(p1.getValue())) { returnNormal(new logical(false)); } @@ -250,8 +249,8 @@ returnNormal(new logical(false)); } - returnNormal(new logical(entries[0].toLowerCase().equals("application") - && entries[1].toLowerCase().equals("json"))); + returnNormal(new logical(entries[0].equalsIgnoreCase("application") + && entries[1].equalsIgnoreCase("json"))); })); } @@ -272,7 +271,7 @@ return function(MimeTypeHelper.class, "IsXML", logical.class, new Block((Body) () -> { - if (p1.isUnknown() || StringUtils.isBlank(p1.getValue())) + if (p1.isUnknown() || TextOps.isEmpty(p1.getValue())) { returnNormal(new logical(false)); } @@ -284,13 +283,13 @@ returnNormal(new logical(false)); } - if (entries[0].toLowerCase().equals("application")) - returnNormal(new logical(entries[1].toLowerCase().equals("xml") - || entries[1].toLowerCase().equals("xml-external-parsed-entity") - || entries[1].toLowerCase().equals("xml-dtd"))); + if (entries[0].equalsIgnoreCase("application")) + returnNormal(new logical(entries[1].equalsIgnoreCase("xml") + || entries[1].equalsIgnoreCase("xml-external-parsed-entity") + || entries[1].equalsIgnoreCase("xml-dtd"))); - returnNormal(new logical(entries[0].toLowerCase().equals("text") - && entries[1].toLowerCase().equals("xml-external-parsed-entity"))); + returnNormal(new logical(entries[0].equalsIgnoreCase("text") + && entries[1].equalsIgnoreCase("xml-external-parsed-entity"))); })); } === modified file 'src/com/goldencode/p2j/oo/net/MultipartEntity.java' --- src/com/goldencode/p2j/oo/net/MultipartEntity.java 2020-04-15 21:35:28 +0000 +++ src/com/goldencode/p2j/oo/net/MultipartEntity.java 2020-11-23 06:49:44 +0000 @@ -9,6 +9,7 @@ ** 002 IAS 20190527 Added multipart support. ** 003 CA 20191024 Added method support levels and updated the class support level. ** 004 ME 20200414 Complete implementation as per OE 11.7.4. +** 20201123 Assert positive index on remove (OE 12.2). */ /* @@ -384,6 +385,8 @@ return function(this, "RemovePart", logical.class, new Block((Body) () -> { + Assert.isPositive(n, new character("Part num")); + boolean found = this.parts.removeIf(p -> p.num == n.intValue()); if (found) === modified file 'src/com/goldencode/p2j/oo/net/Uri.java' --- src/com/goldencode/p2j/oo/net/Uri.java 2021-01-13 15:36:44 +0000 +++ src/com/goldencode/p2j/oo/net/Uri.java 2021-01-31 10:14:52 +0000 @@ -12,6 +12,7 @@ ** 005 CA 20200910 Fixed QueryString property - if missing in the URI, must be empty space and not unknown. ** ME 20200912 Accumulated changes. ** 006 ME 20200925 Rewrite the 4GL way (encode/decode/parse), add missing/new methods as per OE12.2. +** ME 20210111 Only add fragment part to encode if not null or empty. ** CA 20210113 Renamed clear() to clear_(), to follow NameConverter's rules. */ @@ -1254,7 +1255,7 @@ + p1.ref().encodeQuery().getValue(); //fragment - if (!p1.ref().getFragment().isUnknown()) + if (!TextOps.isEmpty(p1.ref().getFragment())) { encodedUri = encodedUri + "#" + encodeFragment(p1.ref().getFragment()).getValue(); } @@ -1425,9 +1426,17 @@ character[] relative = splitUri(p1); + // defaults to HTTP + if (TextOps.isEmpty(relative[_schemePartIdx])) + relative[_schemePartIdx] = UriSchemeEnum.http.ref().toLegacyString(); + + // check authority as this is mandatory + if (TextOps.isEmpty(relative[_authorityPartIdx])) + undoThrow(AppError.newInstance(TextOps.substitute("Unable to parse malformed URI: &1", p1), new integer(0))); + // authority seems to always be decoded relative[_authorityPartIdx] = decode(relative[_authorityPartIdx]); - + // unless false decode by default schema, path, query, fragment if (p2.isUnknown() || p2.booleanValue()) { === modified file 'src/com/goldencode/p2j/oo/net/http/AuthenticatedRequest.java' --- src/com/goldencode/p2j/oo/net/http/AuthenticatedRequest.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/AuthenticatedRequest.java 2020-11-09 08:40:31 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. ** 002 MP 20200603 Added stubs taken by converting the skeleton using FWD +** 003 ME 20201109 Implemented as per OE12.2 (remove callback not buggy as in 4GL). */ /* @@ -76,8 +77,13 @@ import static com.goldencode.p2j.util.BlockManager.onBlockLevel; import static com.goldencode.p2j.util.BlockManager.returnNormal; +import java.util.ArrayList; +import java.util.List; + import com.goldencode.p2j.oo.core.Assert; +import com.goldencode.p2j.oo.net.http.filter.auth.AuthenticationRequestFilter; import com.goldencode.p2j.oo.net.http.filter.auth.IauthFilterEventHandler; +import com.goldencode.p2j.oo.net.http.filter.writer.AuthenticationRequestWriterBuilder; /** * @@ -85,20 +91,22 @@ * */ @LegacyResource(resource = "OpenEdge.Net.HTTP.AuthenticatedRequest") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class AuthenticatedRequest extends HttpRequestDecorator implements IAuthenticatedRequest { @LegacySignature(type = Type.PROPERTY, name = "AuthenticationMethod") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) private character authenticationMethod = TypeFactory.character(); @LegacySignature(type = Type.PROPERTY, name = "Credentials") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) private object credentials = TypeFactory.object(com.goldencode.p2j.oo.net.http.Credentials.class); @LegacySignature(type = Type.PROPERTY, name = "AuthenticationChallenge") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) private character authenticationChallenge = TypeFactory.character(); + + private List> listeners; public void __net_http_AuthenticatedRequest_execute__() { @@ -109,8 +117,6 @@ (Body) () -> { onBlockLevel(Condition.ERROR, Action.THROW); - { - } })); } @@ -118,7 +124,7 @@ { @LegacyParameter(name = "poHttpRequest", type = "OBJECT", qualified = "openedge.net.http.ihttprequest", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_http_AuthenticatedRequest_constructor__( final object _poHttpRequest) { @@ -136,12 +142,23 @@ } @LegacySignature(type = Type.METHOD, name = "AddAuthentication") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void addAuthentication() { internalProcedure(AuthenticatedRequest.class, this, "AddAuthentication", new Block((Body) () -> { - UnimplementedFeature.missing("AuthenticatedRequest:AddAuthentication METHOD"); + object writer = AuthenticationRequestWriterBuilder.build(new object(this), _getAuthenticationCallbacks()); + + if (writer._isValid() && writer.ref() instanceof AuthenticationRequestFilter) + { + AuthenticationRequestFilter authWriter = (AuthenticationRequestFilter) writer.ref(); + + authWriter.open(); + authWriter.flush(); + authWriter.close(); + } + + writer.setUnknown(); })); } @@ -150,7 +167,7 @@ @LegacyParameter(name = "pcAuthMethod", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "pcChallenge", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void setChallenge(final character _pcAuthMethod, final character _pcChallenge) { character pcAuthMethod = TypeFactory.initInput(_pcAuthMethod); @@ -170,7 +187,7 @@ @LegacyParameter(name = "poListener", type = "OBJECT", qualified = "openedge.net.http.filter.auth.iauthfiltereventhandler", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void addAuthenticationCallback( final object _poListener) { @@ -178,7 +195,18 @@ internalProcedure(AuthenticatedRequest.class, this, "AddAuthenticationCallback", new Block((Body) () -> { - UnimplementedFeature.missing("AuthenticatedRequest:AddAuthenticationCallback METHOD"); + Assert.notNull(poListener, new character("Listener")); + + if (listeners == null) + { + listeners = new ArrayList>(); + } + + if (!listeners.contains(poListener)) + { + listeners.add(poListener); + } + })); } @@ -187,7 +215,7 @@ @LegacyParameter(name = "poListener", type = "OBJECT", qualified = "openedge.net.http.filter.auth.iauthfiltereventhandler", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void removeAuthenticationCallback( final object _poListener) { @@ -196,32 +224,45 @@ internalProcedure(AuthenticatedRequest.class, this, "RemoveAuthenticationCallback", new Block((Body) () -> { - UnimplementedFeature.missing("AuthenticatedRequest:RemoveAuthenticationCallback METHOD"); + if (poListener._isValid() && listeners != null) { + listeners.remove(poListener); + } })); } - @LegacySignature(type = Type.METHOD, name = "GetAuthenticationCallbacks", parameters = - { - @LegacyParameter(name = "poListener", type = "OBJECT", extent = -1, - qualified = "openedge.net.http.filter.auth.iauthfiltereventhandler", mode = "OUTPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacySignature(type = Type.METHOD, name = "GetAuthenticationCallbacks", parameters = { + @LegacyParameter(name = "extpoListeners", type = "OBJECT", extent = -1, qualified = "openedge.net.http.filter.auth.iauthfiltereventhandler", mode = "OUTPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public integer getAuthenticationCallbacks( - final OutputExtentParameter> extpoListener) + final OutputExtentParameter> extpoListeners) { - object[] poListener[] = new object[][] - { - TypeFactory.initOutput(extpoListener) - }; - return function(AuthenticatedRequest.class, this, "GetAuthenticationCallbacks", integer.class, new Block((Body) () -> { - UnimplementedFeature.missing("AuthenticatedRequest:GetAuthenticationCallbacks METHOD"); + object[] listeners = extpoListeners + .initParameter(this.listeners == null ? 0 : this.listeners.size()); + + for (int i = 0; i < listeners.length; i++) + { + listeners[i] = this.listeners.get(i); + } + + returnNormal(listeners.length == 0 ? new integer() : new integer(listeners.length)); })); } + private object[] _getAuthenticationCallbacks() { + object[] listeners = TypeFactory.objectExtent(this.listeners == null ? 0 : this.listeners.size(), IauthFilterEventHandler.class); + + for (int i = 0; i < listeners.length; i++) + { + listeners[i].assign(this.listeners.get(i)); + } + + return listeners; + } + @LegacySignature(type = Type.GETTER, name = "AuthenticationMethod") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public character getAuthenticationMethod() { return function(AuthenticatedRequest.class, this, "AuthenticationMethod", character.class, new Block((Body) () -> @@ -231,7 +272,7 @@ } @LegacySignature(type = Type.GETTER, name = "Credentials") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public object getCredentials() { return function(AuthenticatedRequest.class, this, "Credentials", object.class, new Block((Body) () -> @@ -244,7 +285,7 @@ { @LegacyParameter(name = "var", type = "OBJECT", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void setCredentials(final object _var) { object var = TypeFactory.initInput(_var); @@ -256,7 +297,7 @@ } @LegacySignature(type = Type.GETTER, name = "AuthenticationChallenge") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public character getAuthenticationChallenge() { return function(AuthenticatedRequest.class, this, "AuthenticationChallenge", character.class, new Block((Body) () -> === modified file 'src/com/goldencode/p2j/oo/net/http/AuthenticationRequestEventArgs.java' --- src/com/goldencode/p2j/oo/net/http/AuthenticationRequestEventArgs.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/AuthenticationRequestEventArgs.java 2020-11-20 08:38:34 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 ME 20200507 First version. +** 20201120 Cleanup. */ /* @@ -67,8 +68,6 @@ import com.goldencode.p2j.util.BlockManager.Condition; import com.goldencode.p2j.oo.core.Assert; import com.goldencode.p2j.oo.lang.*; -import com.goldencode.p2j.oo.net.http.IhttpRequest; -import com.goldencode.p2j.oo.net.http.Credentials; import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.*; @@ -103,16 +102,6 @@ })); } -// @LegacySignature(type = Type.CONSTRUCTOR) -// public void __net_http_AuthenticationRequestEventArgs_constructor__() -// { -// internalProcedure(AuthenticationRequestEventArgs.class, this, -// "__net_http_AuthenticationRequestEventArgs_constructor__", new Block((Body) () -> -// { -// __lang_BaseObject_constructor__(); -// })); -// } - @LegacySignature(type = Type.GETTER, name = "Request") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object getRequest() @@ -135,20 +124,6 @@ })); } - @LegacySignature(type = Type.SETTER, name = "Realm", parameters = { - @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) - private void setRealm(final character _var) - { - character var = TypeFactory.initInput(_var); - - internalProcedure(AuthenticationRequestEventArgs.class, this, "Realm", - new Block((Body) () -> - { - realm.assign(var); - })); - } - @LegacySignature(type = Type.GETTER, name = "Credentials") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object getCredentials() === modified file 'src/com/goldencode/p2j/oo/net/http/ClientOptions.java' --- src/com/goldencode/p2j/oo/net/http/ClientOptions.java 2019-10-24 23:19:26 +0000 +++ src/com/goldencode/p2j/oo/net/http/ClientOptions.java 2021-01-28 09:57:55 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20191024 Added method support levels and updated the class support level. +** 003 MP 20201217 Implement as of OE12.2. */ /* @@ -65,6 +66,8 @@ package com.goldencode.p2j.oo.net.http; import com.goldencode.p2j.util.*; +import com.goldencode.p2j.util.BlockManager.Action; +import com.goldencode.p2j.util.BlockManager.Condition; import com.goldencode.p2j.oo.lang.*; import static com.goldencode.p2j.util.BlockManager.*; @@ -94,6 +97,7 @@ { externalProcedure(ClientOptions.this, new Block((Body) () -> { + onBlockLevel(Condition.ERROR, Action.THROW); { } })); === modified file 'src/com/goldencode/p2j/oo/net/http/ContentDispositionHeader.java' --- src/com/goldencode/p2j/oo/net/http/ContentDispositionHeader.java 2020-09-16 07:09:16 +0000 +++ src/com/goldencode/p2j/oo/net/http/ContentDispositionHeader.java 2020-11-27 08:19:37 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 MP 20200603 First version, stubs taken by converting the skeleton using FWD. +** 002 ME 20201127 Update support levels. ** */ @@ -68,8 +69,7 @@ import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; -import static com.goldencode.p2j.report.ReportConstants.CVT_LVL_FULL; -import static com.goldencode.p2j.report.ReportConstants.RT_LVL_STUB; +import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.*; import static com.goldencode.p2j.util.InternalEntry.Type; @@ -78,7 +78,7 @@ * in OpenEdge/Net/HTTP/ContentDispositionHeader.cls). */ @LegacyResource(resource = "OpenEdge.Net.HTTP.ContentDispositionHeader") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public class ContentDispositionHeader extends com.goldencode.p2j.oo.net.http.HttpHeader { public void __net_http_ContentDispositionHeader_execute__() @@ -88,7 +88,7 @@ @LegacySignature(type = Type.CONSTRUCTOR, parameters = { @LegacyParameter(name = "pcName", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void __net_http_ContentDispositionHeader_constructor__(final character _pcName) { __net_http_HttpHeader_constructor__(_pcName); @@ -109,7 +109,7 @@ @LegacySignature(type = Type.METHOD, name = "SetParameterValue", parameters = { @LegacyParameter(name = "pcParamName", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "pcParamValue", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) @Override public logical setParameterValue(final character _pcParamName, final character _pcParamValue) { === modified file 'src/com/goldencode/p2j/oo/net/http/ContentTypeHeader.java' --- src/com/goldencode/p2j/oo/net/http/ContentTypeHeader.java 2020-09-16 07:09:16 +0000 +++ src/com/goldencode/p2j/oo/net/http/ContentTypeHeader.java 2020-12-04 08:18:34 +0000 @@ -6,6 +6,8 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. +** 002 ME 20201127 Log info for invalid media types (no error). +** 20201204 Use internalProcedure block for error handling. */ /* @@ -63,7 +65,10 @@ package com.goldencode.p2j.oo.net.http; -import static com.goldencode.p2j.util.BlockManager.externalProcedure; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.*; @@ -81,9 +86,26 @@ * */ @LegacyResource(resource = "OpenEdge.Net.HTTP.ContentTypeHeader") -@LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL | RT_LVL_PARTIAL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL| RT_LVL_FULL) public class ContentTypeHeader extends HttpHeader { + /** Valid Content-Type values */ + private static final Set VALID_TYPES = Collections.unmodifiableSet( + new HashSet() + {{ + add("application"); + add("audio"); + add("image"); + // add("font"); + // add("example"); + add("message"); + //add("model"); + add("multipart"); + add("text"); + add("video"); + }} + ); + /** Header name. */ @LegacySignature(type = Type.PROPERTY, name = "Logger") protected object logger = TypeFactory.object(IlogWriter.class); @@ -93,7 +115,7 @@ */ public void __net_http_ContentTypeHeader_execute__() { - externalProcedure(ContentTypeHeader.this, new Block((Body) () -> { + externalProcedure(ContentTypeHeader.class, ContentTypeHeader.this, new Block((Body) () -> { onBlockLevel(Condition.ERROR, Action.THROW); })); } @@ -107,8 +129,11 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void __net_http_ContentTypeHeader_constructor__(final character name) { - __net_http_HttpHeader_constructor__(name); - this.paramDelimiter.assign(new character(";")); + internalProcedure(ContentTypeHeader.class, this, "__net_http_ContentTypeHeader_constructor__", new Block((Body) () -> + { + __net_http_HttpHeader_constructor__(name); + this.paramDelimiter.assign(new character(";")); + })); } /** @@ -124,7 +149,10 @@ public void __net_http_ContentTypeHeader_constructor__(final character name, final character val) { - __net_http_HttpHeader_constructor__(name, val); + internalProcedure(ContentTypeHeader.class, this, "__net_http_ContentTypeHeader_constructor__", new Block((Body) () -> + { + __net_http_HttpHeader_constructor__(name, val); + })); } /** @@ -138,20 +166,32 @@ @Override protected void validate(final character val) { - super.validate(val); - String sval = val.getValue(); - - if (sval != null && !sval.trim().isEmpty()) - { - sval = TextOps.entries(sval, this.paramDelimiter.getValue())[0]; - - if (sval.indexOf('/') < 0) + internalProcedure(ContentTypeHeader.class, this, "Validate", new Block((Body) () -> { + + super.validate(val); + String sval = val.getValue(); + + if (sval != null && !sval.trim().isEmpty()) { - String msg = String - .format("Header value must have at least 2 \"/\"-delimited parts: %s", sval); - undoThrow(AppError.newInstance(msg, 0)); + sval = TextOps.entries(sval, this.paramDelimiter.getValue())[0]; + int sTypeIdx = sval.indexOf('/'); + + if (sTypeIdx == -1) + { + String msg = String.format( + "Header value must have at least 2 \"/\"-delimited parts: %s", sval); + undoThrow(AppError.newInstance(msg, 0)); + } + + String type = sval.substring(0, sTypeIdx); + + if (!VALID_TYPES.contains(type.toLowerCase())) + { + getLogger().ref().info(TextOps + .substitute("Content-Type header has a non-standard type of &1", type)); + } } - } + })); } @LegacySignature(type = Type.METHOD, name = "SetParameterValue", parameters = { @@ -194,7 +234,7 @@ */ @LegacySignature(type = Type.SETTER, name = "Logger", parameters = { @LegacyParameter(name = "logger", type = "OBJECT", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void setLogger(object logger) { this.logger.assign(logger); === modified file 'src/com/goldencode/p2j/oo/net/http/Cookie.java' --- src/com/goldencode/p2j/oo/net/http/Cookie.java 2020-09-13 21:45:15 +0000 +++ src/com/goldencode/p2j/oo/net/http/Cookie.java 2020-10-28 12:57:17 +0000 @@ -9,6 +9,7 @@ ** RFB 20191022 Added LegacyResource annotation ** 002 CA 20191024 Added method support levels and updated the class support level. ** 003 ME 20200902 Add implementation for methods as per OE12.2. +** 20201028 Use 'now' and 'addInterval', time zone issue in datetime constructor with Calendar. */ /* @@ -95,6 +96,7 @@ import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; import com.goldencode.p2j.util.Body; +import com.goldencode.p2j.util.DateOps; import com.goldencode.p2j.util.InternalEntry.Type; import com.goldencode.p2j.util.LegacyParameter; import com.goldencode.p2j.util.LegacyResource; @@ -365,10 +367,7 @@ { Assert.isZeroOrPositive(maxAge, new character("Cookie max age")); this.maxAge.assign(maxAge); - - Calendar cal = Calendar.getInstance(); - cal.add(Calendar.SECOND, maxAge.intValue()); - expiresAt.assign(new datetimetz(cal)); + expiresAt.assign(DateOps.addInterval(datetimetz.now(), maxAge.longValue(), "seconds")); } if (!expiresAt.isUnknown()) === modified file 'src/com/goldencode/p2j/oo/net/http/CookieCollection.java' --- src/com/goldencode/p2j/oo/net/http/CookieCollection.java 2020-06-15 00:40:59 +0000 +++ src/com/goldencode/p2j/oo/net/http/CookieCollection.java 2021-01-28 10:05:43 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 MP 20200603 First version, stubs taken by converting the skeleton using FWD. +** 002 ME 20210128 Implement remaining methods as of OE12.2. ** */ @@ -68,17 +69,18 @@ import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; -import static com.goldencode.p2j.report.ReportConstants.CVT_LVL_FULL; -import static com.goldencode.p2j.report.ReportConstants.RT_LVL_STUB; +import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.*; import static com.goldencode.p2j.util.InternalEntry.Type; +import com.goldencode.p2j.oo.lang._BaseObject_; + /** * Business logic (converted to Java from the 4GL source code * in OpenEdge/Net/HTTP/CookieCollection.cls). */ @LegacyResource(resource = "OpenEdge.Net.HTTP.CookieCollection") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class CookieCollection extends com.goldencode.p2j.oo.core.collections.LegacyCollection { @@ -93,7 +95,7 @@ } @LegacySignature(type = Type.CONSTRUCTOR) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_http_CookieCollection_constructor__() { internalProcedure(CookieCollection.class, this, "__net_http_CookieCollection_constructor__", new Block((Body) () -> @@ -106,18 +108,12 @@ { @LegacyParameter(name = "poCollection", type = "OBJECT", qualified = "openedge.core.collections.icollection", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void __net_http_CookieCollection_constructor__(final object _poCollection) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void __net_http_CookieCollection_constructor__(final object poCollection) { - object poCollection = TypeFactory.initInput(_poCollection); - - internalProcedure(CookieCollection.class, this, "__net_http_CookieCollection_constructor__", new Block((Init) () -> - { - ObjectOps.register(poCollection); - }, - (Body) () -> - { - __core_collections_LegacyCollection_constructor__(); + internalProcedure(CookieCollection.class, this, "__net_http_CookieCollection_constructor__", new Block((Body) () -> + { + __core_collections_LegacyCollection_constructor__(poCollection); })); } @@ -125,14 +121,12 @@ { @LegacyParameter(name = "newObject", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public logical add_1(final object _newObject) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public logical add_1(final object newObject) { - object newObject = TypeFactory.initInput(_newObject); - return function(CookieCollection.class, this, "Add", logical.class, new Block((Body) () -> { - UnimplementedFeature.missing("CookieCollection:Add METHOD"); + returnNormal(super.add(newObject)); })); } @@ -140,17 +134,12 @@ { @LegacyParameter(name = "poArray", type = "OBJECT", extent = -1, qualified = "openedge.net.http.cookie", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public logical addArray_1(final object[] _poArray) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public logical addArray_1(final object[] poArray) { - object[] poArray[] = new object[][] - { - TypeFactory.initInput(_poArray) - }; - return function(CookieCollection.class, this, "AddArray", logical.class, new Block((Body) () -> { - UnimplementedFeature.missing("CookieCollection:AddArray METHOD"); + returnNormal(super.addArray(poArray)); })); } @@ -158,14 +147,12 @@ { @LegacyParameter(name = "oldObject", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public logical remove_1(final object _oldObject) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public logical remove_1(final object oldObject) { - object oldObject = TypeFactory.initInput(_oldObject); - return function(CookieCollection.class, this, "Remove", logical.class, new Block((Body) () -> { - UnimplementedFeature.missing("CookieCollection:Remove METHOD"); + returnNormal(super.remove(oldObject)); })); } @@ -173,24 +160,31 @@ { @LegacyParameter(name = "checkObject", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public logical contains_1(final object _checkObject) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public logical contains_1(final object checkObject) { - object checkObject = TypeFactory.initInput(_checkObject); - return function(CookieCollection.class, this, "Contains", logical.class, new Block((Body) () -> { - UnimplementedFeature.missing("CookieCollection:Contains METHOD"); + returnNormal(super.contains(checkObject)); })); } @LegacySignature(type = Type.METHOD, name = "ToCookieArray", extent = -1, qualified = "openedge.net.http.cookie") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object[] toCookieArray() { - return extentFunction(CookieCollection.class, this, "ToCookieArray", object.class, new Block((Body) () -> - { - UnimplementedFeature.missing("CookieCollection:ToCookieArray METHOD"); - })); + return extentFunction(CookieCollection.class, this, "ToCookieArray", object.class, + new Block((Body) () -> { + object[] arr = super.toArray(); + object[] cookies = TypeFactory + .objectExtent(arr.length, Cookie.class); + + for (int i = 0; i < cookies.length; i++) + { + cookies[i].assign(ObjectOps.cast(arr[i], Cookie.class)); + } + + returnExtentNormal(cookies); + })); } } === modified file 'src/com/goldencode/p2j/oo/net/http/CookieJar.java' --- src/com/goldencode/p2j/oo/net/http/CookieJar.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/CookieJar.java 2020-10-28 11:28:34 +0000 @@ -8,6 +8,7 @@ ** 001 IAS 20190923 First version. ** 002 ME 20200410 Implement ILogger interface fully. ** 003 MP 20200611 Complete class with stubs taken by converting the skeleton using FWD. +** 004 ME 20201028 Implement all methods as per OE12.2. */ /* @@ -66,8 +67,12 @@ package com.goldencode.p2j.oo.net.http; import com.goldencode.p2j.oo.core.*; +import com.goldencode.p2j.oo.json.objectmodel.JsonArray; +import com.goldencode.p2j.oo.json.objectmodel.JsonObject; +import com.goldencode.p2j.oo.json.objectmodel.ObjectModelParser; import com.goldencode.p2j.oo.lang.*; import com.goldencode.p2j.oo.logging.*; +import com.goldencode.p2j.security.ContextLocal; import com.goldencode.p2j.util.*; import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; @@ -76,30 +81,80 @@ import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; + /** * * Stores cookies temporarily and persistently. * */ @LegacyResource(resource = "OpenEdge.Net.HTTP.CookieJar") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_PARTIAL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public class CookieJar extends BaseObject implements ICookieJar, ISupportInitialize, ISupportLogging { + private class CookieJarEntry + { + final object cookie; + final String domain; + final String path; + final String name; + + final datetimetz created = TypeFactory.datetimetz(); + final datetimetz lastAccess = TypeFactory.datetimetz(); + + CookieJarEntry(object cookie, String domain, String path) + { + this(cookie, domain, path, datetimetz.now(), TypeFactory.datetimetz()); + } + + CookieJarEntry(object cookie, String domain, String path, datetimetz created, datetimetz lastAccess) + { + this.cookie = cookie; + this.name = cookie.ref().getName().getValue(); + this.domain = domain; + this.path = TextOps.isEmpty(path) ? "/" : path; + + this.created.assign(created); + this.lastAccess.assign(lastAccess); + } + } + + private final static String TAG_COOKIES = "cookies"; + private final static String TAG_COOKIE_NAME = "CookieName"; + private final static String TAG_COOKIE_DOMAIN = "Domain"; + private final static String TAG_COOKIE_PATH = "Path"; + private final static String TAG_COOKIE_DATA = "Cookie"; + private final static String TAG_COOKIE_CREATED = "CreatedAt"; + private final static String TAG_COOKIE_ACCESS = "LastAccessedAt"; + @LegacySignature(type = Type.PROPERTY, name = "Logger") private final object logger = TypeFactory.object(IlogWriter.class); - + @LegacySignature(type = Type.PROPERTY, name = "CookieJarPath") private character cookieJarPath = TypeFactory.character(); - + + // persistent are stored as static for client session + private static ContextLocal> persistentCookies = new ContextLocal>() + { + protected List initialValue() + { + return new ArrayList(); + } + }; + + // session cookies are stored only for the jar lifetime + private List sessionCookies = new ArrayList(); + public void __net_http_CookieJar_execute__() { - externalProcedure(CookieJar.class, CookieJar.this, new Block((Body) () -> - { + externalProcedure(CookieJar.class, CookieJar.this, new Block((Body) () -> { onBlockLevel(Condition.ERROR, Action.THROW); - { - } })); } @@ -113,8 +168,7 @@ @Override public object getLogger() { - return function(this, "Logger", object.class, new Block((Body) () -> - { + return function(this, "Logger", object.class, new Block((Body) () -> { returnNormal(logger); })); } @@ -123,13 +177,12 @@ * Destroy */ @LegacySignature(type = Type.METHOD, name = "Destroy") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) @Override public void destroy() { - internalProcedure(CookieJar.class, this, "Destroy", new Block((Body) () -> - { - CookieJar.persistCookieJar(this.cookieJarPath); + internalProcedure(CookieJar.class, this, "Destroy", new Block((Body) () -> { + _persistCookies(); })); } @@ -137,16 +190,37 @@ * Initialize */ @LegacySignature(type = Type.METHOD, name = "Initialize") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) @Override public void initialize() { - internalProcedure(CookieJar.class, this, "Initialize", new Block((Body) () -> - { - UnimplementedFeature.missing("CookieJar:Initialize METHOD"); + internalProcedure(CookieJar.class, this, "Initialize", new Block((Body) () -> { + // load persisted cookies, no-op if file not found + character jarStore = FileSystemOps.searchPath(cookieJarPath); + + if (jarStore.isUnknown()) + return; + + object parser = ObjectOps.newInstance(ObjectModelParser.class); + object data = ObjectOps.cast(parser.ref().parseFile(jarStore), JsonObject.class); + + if (data.ref().has(new character(TAG_COOKIES)).booleanValue()) { + object cookies = data.ref().getJsonArray(new character(TAG_COOKIES)); + + for (int i = 0; i < cookies.ref().getLength().intValue(); i++) + { + object cookie = cookies.ref().getJsonObject(new integer(i + 1)); + CookieJarEntry entry = new CookieJarEntry(Cookie.parse(cookie.ref().getCharacter(new character(TAG_COOKIE_DATA))), + cookie.ref().getCharacter(new character(TAG_COOKIE_DOMAIN)).getValue(), + cookie.ref().getCharacter(new character(TAG_COOKIE_PATH)).getValue(), + cookie.ref().getDatetimeTz(new character(TAG_COOKIE_CREATED)), + cookie.ref().getDatetimeTz(new character(TAG_COOKIE_ACCESS))); + + _addCookie(entry, persistentCookies.get()); + } + } + })); - // TODO Auto-generated method stub - } /** @@ -160,187 +234,325 @@ public void setLogger(object _logger) { object logger = TypeFactory.initInput(_logger); - - internalProcedure(this, "Logger", new Block((Body) () -> - { + + internalProcedure(this, "Logger", new Block((Body) () -> { this.logger.assign(logger); })); } - + @LegacySignature(type = Type.GETTER, name = "CookieJarPath") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public character getCookieJarPath() { - return function(CookieJar.class, this, "CookieJarPath", character.class, new Block((Body) () -> - { - returnNormal(cookieJarPath); - })); + return function(CookieJar.class, this, "CookieJarPath", character.class, + new Block((Body) () -> { + returnNormal(cookieJarPath); + })); } - @LegacySignature(type = Type.SETTER, name = "CookieJarPath", parameters = - { - @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacySignature(type = Type.SETTER, name = "CookieJarPath", parameters = { + @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void setCookieJarPath(final character _var) { character var = TypeFactory.initInput(_var); - - internalProcedure(CookieJar.class, this, "CookieJarPath", new Block((Body) () -> - { + + internalProcedure(CookieJar.class, this, "CookieJarPath", new Block((Body) () -> { cookieJarPath.assign(var); })); } - + @LegacySignature(type = Type.CONSTRUCTOR) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void __net_http_CookieJar_constructor__() { - internalProcedure(CookieJar.class, this, "__net_http_CookieJar_constructor__", new Block((Body) () -> - { - __lang_BaseObject_constructor__(); - })); + internalProcedure(CookieJar.class, this, "__net_http_CookieJar_constructor__", + new Block((Body) () -> { + __lang_BaseObject_constructor__(); + cookieJarPath.assign(TextOps.substitute("&1cookies.json", + EnvironmentOps.getTempDirectory())); + logger.assign(ObjectOps.newInstance(VoidLogger.class)); + })); } @LegacySignature(type = Type.DESTRUCTOR) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void __net_http_CookieJar_destructor__() { - internalProcedure(CookieJar.class, this, "__net_http_CookieJar_destructor__", new Block((Body) () -> - { - this.destroy(); - })); + internalProcedure(CookieJar.class, this, "__net_http_CookieJar_destructor__", + new Block((Body) () -> { + this.destroy(); + })); } - - @LegacySignature(type = Type.METHOD, name = "AddCookie", parameters = - { - @LegacyParameter(name = "pcDomain", type = "CHARACTER", mode = "INPUT"), - @LegacyParameter(name = "pcPath", type = "CHARACTER", mode = "INPUT"), - @LegacyParameter(name = "poCookie", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) - public void addCookie(final character _pcDomain, final character _pcPath, final object _poCookie) + + @LegacySignature(type = Type.METHOD, name = "AddCookie", parameters = { + @LegacyParameter(name = "pcDomain", type = "CHARACTER", mode = "INPUT"), + @LegacyParameter(name = "pcPath", type = "CHARACTER", mode = "INPUT"), + @LegacyParameter(name = "poCookie", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void addCookie(final character _pcDomain, final character _pcPath, + final object _poCookie) { character pcDomain = TypeFactory.initInput(_pcDomain); character pcPath = TypeFactory.initInput(_pcPath); - object poCookie = TypeFactory.initInput(_poCookie); - - internalProcedure(CookieJar.class, this, "AddCookie", new Block((Body) () -> - { - UnimplementedFeature.missing("CookieJar:AddCookie 1 METHOD"); + object poCookie = TypeFactory + .initInput(_poCookie); + + internalProcedure(CookieJar.class, this, "AddCookie", new Block((Body) () -> { + Assert.notNull(poCookie, new character("Cookie")); + + // no error thrown if domain doesn't match + if (pcDomain.isUnknown() + || pcDomain.getValue().endsWith(poCookie.ref().getDomain().getValue())) + { + Assert.notNullOrEmpty(pcDomain, new character("Cookie Domain")); + Assert.notNull(pcPath, new character("Cookie Path")); + + CookieJarEntry entry = new CookieJarEntry(poCookie, pcDomain.getValue(), + pcPath.getValue()); + + // no expiration set, session cookie + if (poCookie.ref().getExpiresAt().isUnknown()) + { + _addCookie(entry, sessionCookies); + } + else + { + // don't save it if expired already + if (!_isExpired(poCookie.ref())) + _addCookie(entry, persistentCookies.get()); + } + } + else if (logger._isValid()) + { + logger.ref().debug(TextOps.substitute("Bad domain &1 for &2", pcDomain, poCookie)); + } })); } - @LegacySignature(type = Type.METHOD, name = "AddCookie", parameters = - { - @LegacyParameter(name = "poCookie", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacySignature(type = Type.METHOD, name = "AddCookie", parameters = { + @LegacyParameter(name = "poCookie", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void addCookie(final object _poCookie) { - object poCookie = TypeFactory.initInput(_poCookie); - - internalProcedure(CookieJar.class, this, "AddCookie", new Block((Body) () -> - { - UnimplementedFeature.missing("CookieJar:AddCookie METHOD"); + object poCookie = TypeFactory + .initInput(_poCookie); + + internalProcedure(CookieJar.class, this, "AddCookie", new Block((Body) () -> { + Assert.notNull(poCookie, new character("Cookie")); + addCookie(poCookie.ref().getDomain(), _poCookie.ref().getPath(), _poCookie); })); } - @LegacySignature(type = Type.METHOD, name = "AddCookies", parameters = - { - @LegacyParameter(name = "poCookies", type = "OBJECT", extent = -1, qualified = "openedge.net.http.cookie", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) - public void addCookies(final object[] _poCookies) - { - object[] poCookies[] = new object[][] - { - TypeFactory.initInput(_poCookies) - }; - - internalProcedure(CookieJar.class, this, "AddCookies", new Block((Body) () -> - { - UnimplementedFeature.missing("CookieJar:AddCookies METHOD"); + @LegacySignature(type = Type.METHOD, name = "AddCookies", parameters = { + @LegacyParameter(name = "poCookies", type = "OBJECT", extent = -1, qualified = "openedge.net.http.cookie", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void addCookies( + final object[] _poCookies) + { + object[] poCookies = TypeFactory + .initInput(_poCookies); + + internalProcedure(CookieJar.class, this, "AddCookies", new Block((Body) () -> { + Assert.notNull(poCookies, new character("Cookies")); + + for (int i = 0; i < poCookies.length; i++) + { + addCookie(poCookies[i]); + } })); } @LegacySignature(type = Type.METHOD, name = "ClearPersistentCookies") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void clearPersistentCookies() { - internalProcedure(CookieJar.class, this, "ClearPersistentCookies", new Block((Body) () -> - { - UnimplementedFeature.missing("CookieJar:ClearPersistentCookies METHOD"); + internalProcedure(CookieJar.class, this, "ClearPersistentCookies", new Block((Body) () -> { + persistentCookies.get().clear(); + _persistCookies(); + + if (logger._isValid()) + logger.ref().debug(TextOps.substitute("Cleared persistent cookies: &1", datetimetz.now())); })); } @LegacySignature(type = Type.METHOD, name = "ClearSessionCookies") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void clearSessionCookies() { - internalProcedure(CookieJar.class, this, "ClearSessionCookies", new Block((Body) () -> - { - UnimplementedFeature.missing("CookieJar:ClearSessionCookies METHOD"); + internalProcedure(CookieJar.class, this, "ClearSessionCookies", new Block((Body) () -> { + sessionCookies.clear(); + if (logger._isValid()) + logger.ref().debug(TextOps.substitute("Cleared session cookies: &1", datetimetz.now())); })); } @LegacySignature(type = Type.CONSTRUCTOR) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public static void __net_http_CookieJar_constructor__static__() { - externalProcedure(CookieJar.class, new Block((Body) () -> - { + externalProcedure(CookieJar.class, new Block((Body) () -> { onBlockLevel(Condition.ERROR, Action.THROW); - { - } })); } - @LegacySignature(type = Type.METHOD, name = "GetCookies", parameters = - { - @LegacyParameter(name = "poUri", type = "OBJECT", qualified = "openedge.net.uri", mode = "INPUT"), - @LegacyParameter(name = "poCookies", type = "OBJECT", extent = -1, qualified = "openedge.net.http.cookie", mode = "OUTPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) - public integer getCookies(final object _poUri, final OutputExtentParameter> extpoCookies) + @LegacySignature(type = Type.METHOD, name = "GetCookies", parameters = { + @LegacyParameter(name = "poUri", type = "OBJECT", qualified = "openedge.net.uri", mode = "INPUT"), + @LegacyParameter(name = "poCookies", type = "OBJECT", extent = -1, qualified = "openedge.net.http.cookie", mode = "OUTPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public integer getCookies(final object _poUri, + final OutputExtentParameter> extpoCookies) { object poUri = TypeFactory.initInput(_poUri); - object[] poCookies[] = new object[][] - { - TypeFactory.initOutput(extpoCookies) - }; - - return function(CookieJar.class, this, "GetCookies", integer.class, new Block((Body) () -> - { - UnimplementedFeature.missing("CookieJar:GetCookies METHOD"); - })); - } - - @LegacySignature(type = Type.METHOD, name = "RemoveCookie", parameters = - { - @LegacyParameter(name = "poCookie", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) - public logical removeCookie(final object _poCookie) - { - object poCookie = TypeFactory.initInput(_poCookie); - - return function(CookieJar.class, this, "RemoveCookie", logical.class, new Block((Body) () -> - { - UnimplementedFeature.missing("CookieJar:RemoveCookie METHOD"); - })); + + return function(CookieJar.class, this, "GetCookies", integer.class, new Block((Body) () -> { + String domain = poUri.ref().getHost().getValue().toLowerCase(); + String path = poUri.ref().getPath().getValue().toLowerCase(); + String scheme = poUri.ref().getScheme().getValue(); + + boolean secure = "https".equalsIgnoreCase(scheme); + boolean http = secure || "http".equalsIgnoreCase(scheme); + + ArrayList> all = new ArrayList>(); + + // persistent first + all.addAll(_getCookies(persistentCookies.get(), domain, path, http, secure)); + all.addAll(_getCookies(sessionCookies, domain, path, http, secure)); + + object[] cookies = extpoCookies.initParameter(all.size()); + + for (int i = 0; i < cookies.length; i++) + { + cookies[i] = all.get(i); + } + + returnNormal(new integer(cookies.length)); + })); + } + + @LegacySignature(type = Type.METHOD, name = "RemoveCookie", parameters = { + @LegacyParameter(name = "poCookie", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public logical removeCookie( + final object _poCookie) + { + object poCookie = TypeFactory + .initInput(_poCookie); + + return function(CookieJar.class, this, "RemoveCookie", logical.class, + new Block((Body) () -> { + Assert.notNull(poCookie, new character("Cookie")); + + returnNormal(new logical(_removeCookie(poCookie.ref(), sessionCookies) + || _removeCookie(poCookie.ref(), persistentCookies.get()))); + })); + } + + private boolean _removeCookie(Cookie cookie, + List store) + { + + Optional entry = store.stream() + .filter(e -> e.domain.equalsIgnoreCase(cookie.getDomain().getValue()) + && e.path.equalsIgnoreCase(cookie.getPath().getValue()) + && e.name.equalsIgnoreCase(cookie.getName().getValue())) + .findFirst(); + + if (entry.isPresent()) { + return store.remove(entry.get()); + } + + return false; + } + + private void _addCookie(CookieJarEntry cookie, List store) + { + Optional entry = store.stream() + .filter(e -> e.domain.equalsIgnoreCase(cookie.domain) + && e.path.equalsIgnoreCase(cookie.path) + && e.name.equalsIgnoreCase(cookie.name)) + .findFirst(); + + if (entry.isPresent()) + { + // already have a cookie with same name for domain/path pair + entry.get().cookie.assign(cookie.cookie); + } + else + { + store.add(cookie); + } + } + + private boolean _isExpired(Cookie cookie) + { + + return !cookie.getExpiresAt().isUnknown() + && DateOps.compare(cookie.getExpiresAt(), datetimetz.now()) < 0; + } + + private object _serializeCookie(CookieJarEntry poCookie) + { + object jsonObj = ObjectOps.newInstance(JsonObject.class); + + Cookie cookie = poCookie.cookie.ref(); + + jsonObj.ref().add(new character(TAG_COOKIE_NAME), new character(poCookie.name)); + jsonObj.ref().add(new character(TAG_COOKIE_DOMAIN), new character(poCookie.domain)); + jsonObj.ref().add(new character(TAG_COOKIE_PATH), new character(poCookie.path)); + jsonObj.ref().add(new character(TAG_COOKIE_DATA), cookie.toLegacyString()); + jsonObj.ref().add(new character(TAG_COOKIE_CREATED), poCookie.created); + jsonObj.ref().add(new character(TAG_COOKIE_ACCESS), poCookie.lastAccess); + + return jsonObj; + } + + private Collection> _getCookies(List store, + String domain, String path, boolean http, boolean secure) + { + + ArrayList> cookies = new ArrayList>(); + + for (Iterator iterator = store.iterator(); iterator.hasNext();) + { + CookieJarEntry cookieJarEntry = (CookieJarEntry) iterator.next(); + + // match domain and path + if (path.startsWith(cookieJarEntry.path.toLowerCase()) + && (cookieJarEntry.domain.equalsIgnoreCase(domain) + || (cookieJarEntry.domain.indexOf('.') == 0 + && domain.endsWith(cookieJarEntry.domain.toLowerCase())))) + { + Cookie cookie = cookieJarEntry.cookie.ref(); + // check expiration + if (_isExpired(cookie)) + { + // already expired, no point in keeping it around + iterator.remove(); + } + // check if http only/secure is set on cookie + else if ((!cookie.getHttpOnly().booleanValue() || http) + && (!cookie.getSecure().booleanValue() || secure)) + { + cookies.add(cookieJarEntry.cookie); + } + } + } + + return cookies; } - @LegacySignature(type = Type.METHOD, name = "PersistCookieJar") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) - private static void persistCookieJar(final character _cookieJarPath) - { - character cookieJarPath = TypeFactory.initInput(_cookieJarPath); - internalProcedure(CookieJar.class, "PersistCookieJar", new Block((Body) () -> - { - UnimplementedFeature.missing("CookieJar:PersistCookieJar METHOD"); - })); + private void _persistCookies () { + final object jsonObj = ObjectOps.newInstance(JsonObject.class); + final object jsonArr = ObjectOps.newInstance(JsonArray.class); + + persistentCookies.get().stream() + .filter(c -> c.cookie._isValid() && !_isExpired(c.cookie.ref())) + .forEach(c -> jsonArr.ref().add_2(_serializeCookie(c))); + + jsonObj.ref().add(new character(TAG_COOKIES), jsonArr); + + jsonObj.ref().writeFile(cookieJarPath); } - } === modified file 'src/com/goldencode/p2j/oo/net/http/CookieJarBuilder.java' --- src/com/goldencode/p2j/oo/net/http/CookieJarBuilder.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/CookieJarBuilder.java 2020-10-28 14:50:14 +0000 @@ -8,6 +8,7 @@ ** 001 IAS 20190923 First version. ** 002 ME 20200410 Added missing build method and getCookieJar abstract. ** 003 MP 20200611 Added missing methods as stubs taken by converting the skeleton using FWD. +** 004 ME 20201028 Implement missing methods as of OE12.2. */ /* @@ -89,10 +90,12 @@ * */ @LegacyResource(resource = "OpenEdge.Net.HTTP.CookieJarBuilder") -@LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL|RT_LVL_PARTIAL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public abstract class CookieJarBuilder extends com.goldencode.p2j.oo.net.http.ConfigBuilder { + protected static final String OPTION_PERSIST_TO = "cookieJarPath"; + /** Registry */ @LegacySignature(type = Type.PROPERTY, name = "Registry") private static ContextLocal> registry = new ContextLocal>() @@ -124,7 +127,11 @@ if(!oRegistry._isValid()) { oRegistry.assign(ObjectOps.newInstance(BuilderRegistry.class)); - initializeRegistry(oRegistry); + + oRegistry.ref().put(new character(ObjectOps.getLegacyName(CookieJarBuilder.class)), + ObjectOps.getLegacyClass(DefaultCookieJarBuilder.class)); + oRegistry.ref().put(new character(ObjectOps.getLegacyName(ICookieJar.class)), + ObjectOps.getLegacyClass(CookieJar.class)); } returnNormal(oRegistry); })); @@ -139,27 +146,6 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public abstract object getCookieJar(); - /** - * Initialize registry - * - * @param _poRegistry registry to be initialized - */ - @LegacySignature(type = Type.METHOD, name = "InitializeRegistry", parameters = - { - @LegacyParameter(name = "poRegistry", type = "OBJECT", - qualified = "openedge.net.http.builderregistry", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - private static void initializeRegistry(final object _poRegistry) - { - - internalProcedure(null, "InitializeRegistry", new Block((Body) ()-> { - _poRegistry.ref().put(new character(ObjectOps.getLegacyName(CookieJarBuilder.class)), - ObjectOps.getLegacyClass(DefaultCookieJarBuilder.class)); - _poRegistry.ref().put(new character(ObjectOps.getLegacyName(ICookieJar.class)), - ObjectOps.getLegacyClass(CookieJar.class)); - })); - } /** * Builder director method. @@ -167,7 +153,7 @@ * @return A builder for the requested type. */ @LegacySignature(type = Type.METHOD, name = "Build", qualified = "OpenEdge.Net.HTTP.CookieJarBuilder") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static object build() { return function(CookieJarBuilder.class, "Build", object.class, new Block((Body)() -> @@ -181,7 +167,7 @@ object oCJB = (object) ObjectOps.newInstance(oBuilderType.ref().getType()); - if (!oCJB.isUnknown() && oCJB.ref() instanceof ISupportInitialize) + if (oCJB._isValid() && oCJB.ref() instanceof ISupportInitialize) ((ISupportInitialize) oCJB.ref()).initialize(); returnNormal(oCJB); @@ -206,11 +192,12 @@ } @LegacySignature(type = Type.CONSTRUCTOR) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_http_CookieJarBuilder_constructor__() { internalProcedure(CookieJarBuilder.class, this, "__net_http_CookieJarBuilder_constructor__", new Block((Body) () -> { + super.__net_http_ConfigBuilder_constructor__(); })); } @@ -227,14 +214,17 @@ { @LegacyParameter(name = "pcCookieJarPath", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public object persistTo(final character _pcCookieJarPath) { character pcCookieJarPath = TypeFactory.initInput(_pcCookieJarPath); return function(CookieJarBuilder.class, this, "PersistTo", object.class, new Block((Body)() -> { - UnimplementedFeature.missing("CookieJarBuilder:PersistTo METHOD"); + Assert.notNullOrEmpty(pcCookieJarPath, new character("Cookie Jar Persistence Path")); + setOption(new character(OPTION_PERSIST_TO), pcCookieJarPath); + + returnNormal(new object(this)); })); } @@ -243,7 +233,7 @@ @LegacyParameter(name = "poDecorationType", type = "OBJECT", qualified = "progress.lang.class", mode = "INPUT"), @LegacyParameter(name = "poDecoratedClient", type = "OBJECT", qualified = "openedge.net.http.icookiejar", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static object decorateCookieJar(final object _poDecorationType, final object _poDecoratedClient) { object poDecorationType = TypeFactory.initInput(_poDecorationType); @@ -251,7 +241,21 @@ return function(CookieJarBuilder.class, "DecorateCookieJar", object.class, new Block((Body)() -> { - UnimplementedFeature.missing("CookieJarBuilder:DecorateCookieJar METHOD"); + object oType = getRegistry().ref() + .get(poDecorationType.ref().getTypeName()); + + if (!oType._isValid()) + returnNormal(poDecoratedClient); + + Assert.isType(oType, ObjectOps.getLegacyClass(CookieJarDecorator.class)); + + object decoratedClient = ObjectOps.newInstance(oType.ref().getType(), "I", poDecoratedClient); + + if (decoratedClient._isValid() && decoratedClient.ref() instanceof ISupportInitialize) + ((ISupportInitialize) decoratedClient.ref()).initialize(); + + returnNormal(decoratedClient); + })); } } === modified file 'src/com/goldencode/p2j/oo/net/http/CookieJarDecorator.java' --- src/com/goldencode/p2j/oo/net/http/CookieJarDecorator.java 2020-06-15 00:40:59 +0000 +++ src/com/goldencode/p2j/oo/net/http/CookieJarDecorator.java 2020-10-29 08:07:50 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 MP 20200603 Added stubs taken by converting the skeleton using FWD +** 002 ME 20201028 Implement as per OE12.2. */ /* @@ -66,10 +67,10 @@ import com.goldencode.p2j.util.*; import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; +import com.goldencode.p2j.oo.core.Assert; import com.goldencode.p2j.oo.lang.*; -import static com.goldencode.p2j.report.ReportConstants.CVT_LVL_FULL; -import static com.goldencode.p2j.report.ReportConstants.RT_LVL_STUB; +import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.*; import static com.goldencode.p2j.util.InternalEntry.Type; @@ -78,27 +79,19 @@ * in OpenEdge/Net/HTTP/CookieJarDecorator.cls). */ @LegacyResource(resource = "OpenEdge.Net.HTTP.CookieJarDecorator") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public abstract class CookieJarDecorator extends BaseObject implements com.goldencode.p2j.oo.net.http.ICookieJar { @LegacySignature(type = Type.PROPERTY, name = "DecoratedCookieJar") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) private object decoratedCookieJar = TypeFactory.object(com.goldencode.p2j.oo.net.http.ICookieJar.class); - @LegacySignature(type = Type.PROPERTY, name = "CookieJarPath") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - private character cookieJarPath = TypeFactory.character(); - public void __net_http_CookieJarDecorator_execute__() { - externalProcedure(CookieJarDecorator.class, CookieJarDecorator.this, new Block((Init) () -> - { - ObjectOps.register(decoratedCookieJar); - }, - (Body) () -> + externalProcedure(CookieJarDecorator.class, CookieJarDecorator.this, new Block((Body) () -> { onBlockLevel(Condition.ERROR, Action.THROW); { @@ -107,7 +100,7 @@ } @LegacySignature(type = Type.GETTER, name = "DecoratedCookieJar") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) protected object getDecoratedCookieJar() { return function(CookieJarDecorator.class, this, "DecoratedCookieJar", object.class, new Block((Body) () -> @@ -117,12 +110,12 @@ } @LegacySignature(type = Type.GETTER, name = "CookieJarPath") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public character getCookieJarPath() { return function(CookieJarDecorator.class, this, "CookieJarPath", character.class, new Block((Body) () -> { - returnNormal(cookieJarPath); + returnNormal(decoratedCookieJar.ref().getCookieJarPath()); })); } @@ -130,14 +123,12 @@ { @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void setCookieJarPath(final character _var) { - character var = TypeFactory.initInput(_var); - internalProcedure(CookieJarDecorator.class, this, "CookieJarPath", new Block((Body) () -> { - cookieJarPath.assign(var); + decoratedCookieJar.ref().setCookieJarPath(_var); })); } @@ -145,18 +136,18 @@ { @LegacyParameter(name = "poCookieJar", type = "OBJECT", qualified = "openedge.net.http.icookiejar", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_http_CookieJarDecorator_constructor__(final object _poCookieJar) { object poCookieJar = TypeFactory.initInput(_poCookieJar); - internalProcedure(CookieJarDecorator.class, this, "__net_http_CookieJarDecorator_constructor__", new Block((Init) () -> - { - ObjectOps.register(poCookieJar); - }, + internalProcedure(CookieJarDecorator.class, this, "__net_http_CookieJarDecorator_constructor__", new Block( (Body) () -> { __lang_BaseObject_constructor__(); + + Assert.notNull(poCookieJar, new character("Cookie Jar")); + this.decoratedCookieJar.assign(poCookieJar); })); } @@ -165,20 +156,14 @@ @LegacyParameter(name = "poUri", type = "OBJECT", qualified = "openedge.net.uri", mode = "INPUT"), @LegacyParameter(name = "poCookies", type = "OBJECT", extent = -1, qualified = "openedge.net.http.cookie", mode = "OUTPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public integer getCookies( final object _poUri, final OutputExtentParameter> extpoCookies) { - object poUri = TypeFactory.initInput(_poUri); - object[] poCookies[] = new object[][] - { - TypeFactory.initOutput(extpoCookies) - }; - return function(CookieJarDecorator.class, this, "GetCookies", integer.class, new Block((Body) () -> { - UnimplementedFeature.missing("CookieJarDecorator:GetCookies METHOD"); + returnNormal(decoratedCookieJar.ref().getCookies(_poUri, extpoCookies)); })); } @@ -186,14 +171,17 @@ { @LegacyParameter(name = "poCookie", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void addCookie(final object _poCookie) { object poCookie = TypeFactory.initInput(_poCookie); internalProcedure(CookieJarDecorator.class, this, "AddCookie", new Block((Body) () -> { - UnimplementedFeature.missing("CookieJarDecorator:AddCookie METHOD"); + // for whatever reason this is not a straight pass-through + Assert.notNull(poCookie, new character("Cookie")); + + addCookie(poCookie.ref().getDomain(), poCookie.ref().getPath(), poCookie); })); } @@ -203,19 +191,15 @@ @LegacyParameter(name = "pcPath", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "poCookie", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void addCookie( final character _pcDomain, final character _pcPath, final object _poCookie) { - character pcDomain = TypeFactory.initInput(_pcDomain); - character pcPath = TypeFactory.initInput(_pcPath); - object poCookie = TypeFactory.initInput(_poCookie); - internalProcedure(CookieJarDecorator.class, this, "AddCookie", new Block((Body) () -> { - UnimplementedFeature.missing("CookieJarDecorator:AddCookie METHOD"); + decoratedCookieJar.ref().addCookie(_pcDomain, _pcPath, _poCookie); })); } @@ -223,14 +207,12 @@ { @LegacyParameter(name = "poCookie", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public logical removeCookie(final object _poCookie) { - object poCookie = TypeFactory.initInput(_poCookie); - return function(CookieJarDecorator.class, this, "RemoveCookie", logical.class, new Block((Body) () -> { - UnimplementedFeature.missing("CookieJarDecorator:RemoveCookie METHOD"); + returnNormal(decoratedCookieJar.ref().removeCookie(_poCookie)); })); } @@ -238,37 +220,33 @@ { @LegacyParameter(name = "poCookies", type = "OBJECT", extent = -1, qualified = "openedge.net.http.cookie", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void addCookies(final object[] _poCookies) { - object[] poCookies[] = new object[][] - { - TypeFactory.initInput(_poCookies) - }; - internalProcedure(CookieJarDecorator.class, this, "AddCookies", new Block((Body) () -> { - UnimplementedFeature.missing("CookieJarDecorator:AddCookies METHOD"); + // in 4GL this goes in a loop, probably calls itself instead of method from decorated jar + decoratedCookieJar.ref().addCookies(_poCookies); })); } @LegacySignature(type = Type.METHOD, name = "ClearSessionCookies") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void clearSessionCookies() { internalProcedure(CookieJarDecorator.class, this, "ClearSessionCookies", new Block((Body) () -> { - UnimplementedFeature.missing("CookieJarDecorator:ClearSessionCookies METHOD"); + decoratedCookieJar.ref().clearSessionCookies();; })); } @LegacySignature(type = Type.METHOD, name = "ClearPersistentCookies") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void clearPersistentCookies() { internalProcedure(CookieJarDecorator.class, this, "ClearPersistentCookies", new Block((Body) () -> { - UnimplementedFeature.missing("CookieJarDecorator:ClearPersistentCookies METHOD"); + decoratedCookieJar.ref().clearPersistentCookies(); })); } } === modified file 'src/com/goldencode/p2j/oo/net/http/DefaultCookieJarBuilder.java' --- src/com/goldencode/p2j/oo/net/http/DefaultCookieJarBuilder.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/DefaultCookieJarBuilder.java 2020-10-28 14:57:40 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. ** 002 ME 20200410 Added getter method for cookie jar. +** 20201028 Fix ctor and jar supporting initialization. */ /* @@ -86,13 +87,13 @@ * */ @LegacyResource(resource = "OpenEdge.Net.HTTP.DefaultCookieJarBuilder") -@LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL|RT_LVL_PARTIAL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class DefaultCookieJarBuilder extends CookieJarBuilder { @LegacySignature(type = Type.CONSTRUCTOR) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_http_DefaultCookieJarBuilder_constructor__() { internalProcedure(DefaultCookieJarBuilder.class, this, "__net_http_DefaultCookieJarBuilder_constructor__", new Block((Body) () -> @@ -134,14 +135,14 @@ object cookieJar = (object) ObjectOps.newInstance(cookieJarType.ref().getType()); - if (hasOption(new character("cookieJarPath")).booleanValue()) + if (hasOption(new character(OPTION_PERSIST_TO)).booleanValue()) { - cookieJar.ref().setCookieJarPath(getOptionStringValue(new character("cookieJarPath"))); + cookieJar.ref().setCookieJarPath(getOptionStringValue(new character(OPTION_PERSIST_TO))); } - if (cookieJar instanceof ISupportInitialize) + if (cookieJar.ref() instanceof ISupportInitialize) { - ((ISupportInitialize) cookieJar).initialize(); + ((ISupportInitialize) cookieJar.ref()).initialize(); } returnNormal(cookieJar); === modified file 'src/com/goldencode/p2j/oo/net/http/DefaultHeaderBuilder.java' --- src/com/goldencode/p2j/oo/net/http/DefaultHeaderBuilder.java 2020-06-15 00:40:59 +0000 +++ src/com/goldencode/p2j/oo/net/http/DefaultHeaderBuilder.java 2020-12-04 08:20:35 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. ** 002 ME 20200512 Add header parameters. +** 20201204 Fix function block scope for error handling. */ /* @@ -136,7 +137,7 @@ @Override public object getHeader() { - return function(DefaultHeaderBuilder.class, "Header", object.class, new Block((Body) () -> + return function(DefaultHeaderBuilder.class, this, "Header", object.class, new Block((Body) () -> { if (!this.header._isValid()) { @@ -155,7 +156,7 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) protected object newHeader() { - return function(DefaultHeaderBuilder.class, "NewHeader", object.class, + return function(DefaultHeaderBuilder.class, this, "NewHeader", object.class, new Block((Body) () -> { object hdr = TypeFactory.object(HttpHeader.class); === modified file 'src/com/goldencode/p2j/oo/net/http/DefaultHttpClientBuilder.java' --- src/com/goldencode/p2j/oo/net/http/DefaultHttpClientBuilder.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/DefaultHttpClientBuilder.java 2020-10-23 09:15:39 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. ** 002 ME 20200410 Implement methods as in OE (11.7.4) +** 20201022 Add new protected method newClient (OE 12.2) */ /* @@ -99,7 +100,7 @@ @Override public void destroy() { - // empty in OE implementation + // NOP } /** @@ -123,7 +124,17 @@ @Override public object getClient() { - return function(this, "Client", object.class, new Block((Body) () -> + return newClient(); + } + + /** + * NewClient. + */ + @LegacySignature(type = Type.METHOD, name = "NewClient", qualified = "OpenEdge.Net.HTTP.IHttpClient") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + protected object newClient() + { + return function(this, "NewClient", object.class, new Block((Body) () -> { Assert.isTrue(hasOption(getPropClientName())); Assert.isTrue(hasOption(getPropClientVersion())); @@ -194,7 +205,7 @@ returnNormal(client); })); } - + /** * Constructor. */ === modified file 'src/com/goldencode/p2j/oo/net/http/DefaultRequestBuilder.java' --- src/com/goldencode/p2j/oo/net/http/DefaultRequestBuilder.java 2020-09-13 21:45:15 +0000 +++ src/com/goldencode/p2j/oo/net/http/DefaultRequestBuilder.java 2020-12-07 11:34:04 +0000 @@ -66,27 +66,27 @@ import static com.goldencode.p2j.util.BlockManager.externalProcedure; import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.function; -import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.internalProcedure; -import static com.goldencode.p2j.report.ReportConstants.*; +import static com.goldencode.p2j.util.BlockManager.onBlockLevel; import static com.goldencode.p2j.util.BlockManager.returnNormal; -import static com.goldencode.p2j.report.ReportConstants.*; +import java.util.Comparator; import java.util.Map.*; import com.goldencode.p2j.oo.core.*; -import com.goldencode.p2j.oo.core.collections.*; -import com.goldencode.p2j.oo.json.objectmodel.*; import com.goldencode.p2j.oo.lang.*; import com.goldencode.p2j.oo.net.*; +import com.goldencode.p2j.oo.net.http.filter.auth.IauthFilterEventHandler; import com.goldencode.p2j.util.*; +import com.goldencode.p2j.util.BlockManager.Action; +import com.goldencode.p2j.util.BlockManager.Condition; import com.goldencode.p2j.util.InternalEntry.*; /** * Implementation of non-static methods of the OpenEdge.Net.HTTP.RequestBuilder */ @LegacyResource(resource = "OpenEdge.Net.HTTP.DefaultRequestBuilder") -@LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL|RT_LVL_PARTIAL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class DefaultRequestBuilder extends com.goldencode.p2j.oo.net.http.RequestBuilder { @@ -97,8 +97,7 @@ { externalProcedure(DefaultRequestBuilder.this, new Block((Body) () -> { - { - } + onBlockLevel(Condition.ERROR, Action.THROW); })); } @@ -134,17 +133,7 @@ { return function(this, "Request", object.class, new Block((Body) () -> { - returnNormal(newRequest()); - })); - } - - @LegacySignature(type = Type.GETTER, name = "Request") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_PARTIAL) - private object newRequest() - { - return function(this, "NewRequest", object.class, new Block((Body) () -> - { - object request = TypeFactory.object(IhttpRequest.class); + object request = TypeFactory.object(IhttpRequest.class); object requestType = getRegistry().ref(). _get(ObjectOps.getLegacyName(IhttpRequest.class)); @@ -158,82 +147,76 @@ ObjectOps.cast(request, ISupportInitialize.class).ref().initialize(); } - request.ref().setMethod(getOptionStringValue(new character("method"))); - request.ref().setUri(ObjectOps.cast(getOptionObjectValue(new character("uri")), + request.ref().setMethod(getOptionStringValue(new character(OPTION_METHOD))); + request.ref().setUri(ObjectOps.cast(getOptionObjectValue(new character(OPTION_URI)), Uri.class)); - if (hasOption(new character("version")).booleanValue()) - { - request.ref().setVersion(getOptionStringValue(new character("version"))); - } - else - { - request.ref().setVersion(new character("HTTP/1.1")); + if (_hasOption(OPTION_VERSION)) + { + request.ref().setVersion(getOptionStringValue(new character(OPTION_VERSION))); } - if (hasOption(new character("AcceptContentType")).booleanValue()) + if (_hasOption(OPTION_ACCEPT_CONTENT_TYPE)) { addHeader(new character("Accept"), - TextOps.trim(getOptionStringValue(new character("AcceptContentType")))); + TextOps.trim(getOptionStringValue(new character(OPTION_ACCEPT_CONTENT_TYPE)))); } - else + + if (!_hasOption("header+Accept")) { addHeader(new character("Accept"), new character("*/*")); } - options.entrySet().stream(). - filter(e -> e.getKey().startsWith("header+")).map(Entry::getValue). + options.entrySet().stream().sorted(Comparator.comparing(e -> e.getKey().getValue())). + filter(e -> TextOps._begins(e.getKey(), "header+")).map(Entry::getValue). forEach(h -> request.ref().setHeader( ObjectOps.cast((BaseDataType)h.value(), HttpHeader.class)) ); - options.entrySet().stream(). - filter(e -> e.getKey().startsWith("cookie+")).map(Entry::getValue). + options.entrySet().stream().sorted(Comparator.comparing(e -> e.getKey().getValue())). + filter(e -> TextOps._begins(e.getKey(), "cookie+")).map(Entry::getValue). forEach(h -> request.ref().setCookie( ObjectOps.cast((BaseDataType)h.value(), Cookie.class)) ); - request.ref().setEntity(getOptionObjectValue(new character("entity"))); + request.ref().setEntity(getOptionObjectValue(new character(OPTION_ENTITY))); - if (hasOption(new character("supportsProxy")).booleanValue()) + if (_hasOption(OPTION_SUPPORT_PROXY)) { - // TODO: implement + request.assign(RequestBuilder.decorateRequest(ObjectOps.getLegacyClass(ISupportProxy.class), request)); + if (_hasOption(OPTION_PROXY_URI)) + { + ObjectOps.cast(request, ISupportProxy.class).ref().setProxyUri(ObjectOps.cast(getOptionObjectValue(new character(OPTION_PROXY_URI)), Uri.class)); + } } - if (hasOption(new character("supportsAuthentication")).booleanValue()) + if (_hasOption(OPTION_SUPPORT_AUTHENTICATION)) { - // TODO: implement + request.assign(RequestBuilder.decorateRequest(ObjectOps.getLegacyClass(IAuthenticatedRequest.class), request)); + + IAuthenticatedRequest authReq = ObjectOps.cast(request, IAuthenticatedRequest.class).ref(); + + if (_hasOption(OPTION_AUTH_CREDENTIALS)) + { + authReq.setCredentials(ObjectOps.cast(getOptionObjectValue(new character(OPTION_AUTH_CREDENTIALS)), Credentials.class)); + + if (_hasOption(OPTION_AUTH_METHOD)) + { + authReq.setChallenge(getOptionStringValue(new character(OPTION_AUTH_METHOD)), getOptionStringValue(new character(OPTION_AUTH_CHALLENGE))); + } + } + + if (_hasOption(OPTION_AUTH_LISTENER)) + { + object listener = getOptionObjectValue(new character(OPTION_AUTH_LISTENER)); + if (ObjectOps.typeOf(listener, IauthFilterEventHandler.class).booleanValue()) { + authReq.addAuthenticationCallback(listener); + } + } } returnNormal(request); })); } - /** - * Destroy. - */ - @LegacySignature(type = Type.METHOD, name = "Destroy") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - @Override - public void destroy() - { - internalProcedure(this, "Destroy", new Block((Body) () -> - { - // TODO: implement - })); - } - - /** - * Initialize. - */ - @LegacySignature(type = Type.METHOD, name = "Initialize") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - @Override - public void initialize() - { - internalProcedure(this, "Initialize", new Block((Body) () -> - { - // TODO: implement - })); - } } === modified file 'src/com/goldencode/p2j/oo/net/http/DefaultResponseBuilder.java' --- src/com/goldencode/p2j/oo/net/http/DefaultResponseBuilder.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/DefaultResponseBuilder.java 2020-11-03 09:14:50 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. ** 002 MP 20200611 add missing as stubs taken by converting the skeleton using FWD. +** 003 ME 20201029 Implement as per OE12.2. */ /* @@ -70,6 +71,10 @@ import static com.goldencode.p2j.util.BlockManager.onBlockLevel; import static com.goldencode.p2j.util.BlockManager.returnNormal; +import com.goldencode.p2j.oo.core.Assert; +import com.goldencode.p2j.oo.core.ISupportInitialize; +import com.goldencode.p2j.oo.lang.LegacyClass; +import com.goldencode.p2j.oo.lang._BaseObject_; import com.goldencode.p2j.util.*; import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; @@ -83,20 +88,13 @@ * */ @LegacyResource(resource = "OpenEdge.Net.HTTP.DefaultResponseBuilder") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_PARTIAL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class DefaultResponseBuilder extends com.goldencode.p2j.oo.net.http.ResponseBuilder { - @LegacySignature(type = Type.PROPERTY, name = "Response") - private object response = TypeFactory.object(com.goldencode.p2j.oo.net.http.IhttpResponse.class); - public void __net_http_DefaultResponseBuilder_execute__() { - externalProcedure(DefaultResponseBuilder.class, DefaultResponseBuilder.this, new Block((Init) () -> - { - ObjectOps.register(response); - }, - (Body) () -> + externalProcedure(DefaultResponseBuilder.class, DefaultResponseBuilder.this, new Block((Body) () -> { onBlockLevel(Condition.ERROR, Action.THROW); { @@ -105,17 +103,29 @@ } @LegacySignature(type = Type.GETTER, name = "Response") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_PARTIAL) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public object getResponse() { return function(DefaultResponseBuilder.class, this, "Response", object.class, new Block((Body) () -> { + object responseCls = ObjectOps + .getLegacyClass(IhttpResponse.class); + object responseType = ResponseBuilder.getRegistry().ref() + .get(responseCls.ref().getTypeName()); + + Assert.isType(responseType, responseCls); + + object response = ObjectOps.newInstance(responseType.ref().getType()); + + if (response._isValid() && response.ref() instanceof ISupportInitialize) + ((ISupportInitialize) response.ref()).initialize(); + returnNormal(response); })); } @LegacySignature(type = Type.CONSTRUCTOR) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_PARTIAL) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_http_DefaultResponseBuilder_constructor__() { internalProcedure(DefaultResponseBuilder.class, this, "__net_http_DefaultResponseBuilder_constructor__", new Block((Body) () -> === modified file 'src/com/goldencode/p2j/oo/net/http/HttpClient.java' --- src/com/goldencode/p2j/oo/net/http/HttpClient.java 2020-09-13 21:45:15 +0000 +++ src/com/goldencode/p2j/oo/net/http/HttpClient.java 2021-01-28 09:38:34 +0000 @@ -10,6 +10,8 @@ ** 003 ME 20200410 Added setter method for logger. ** 004 MP 20200602 Added static method instance and static constructor ** 005 MP 20200611 Added missing methods as stub. +** 006 ME 20201103 Added default logger, cookies state management. +** 20210128 Update assert messages, add user agent and retry support. */ /* @@ -75,7 +77,10 @@ import static com.goldencode.p2j.util.BlockManager.returnNormal; import com.goldencode.p2j.oo.core.*; import com.goldencode.p2j.oo.logging.*; +import com.goldencode.p2j.oo.net.http.filter.status.AuthorizationStatusFilter; +import com.goldencode.p2j.oo.net.http.filter.status.RedirectStatusFilter; import com.goldencode.p2j.oo.net.http.filter.writer.*; +import com.goldencode.p2j.ui.LogicalTerminal; import com.goldencode.p2j.util.*; import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; @@ -135,6 +140,7 @@ { internalProcedure(HttpClient.class, this, "Initialize", new Block((Body) () -> { + // no-op (oe12.2) })); } @@ -159,9 +165,9 @@ internalProcedure(this, "__net_http_RequestBuilder_constructor__", new Block((Body) () -> { __lang_BaseObject_constructor__(); - Assert.notNullOrEmpty(_pcClientName); - Assert.notNullOrEmpty(_pcClientVersion); - Assert.notNull(_poLibrary); + Assert.notNullOrEmpty(_pcClientName, new character("Client name")); + Assert.notNullOrEmpty(_pcClientVersion, new character("Client version")); + Assert.notNull(_poLibrary, new character("Http library")); this.clientName.assign(TypeFactory.initInput(_pcClientName)); this.clientVersion.assign(TypeFactory.initInput(_pcClientVersion)); this.library.assign(TypeFactory.initInput(_poLibrary)); @@ -197,18 +203,21 @@ })); } - @LegacySignature(type = Type.METHOD, name = "AddUserAgent", parameters = - { - @LegacyParameter(name = "p1", type = "OBJECT", qualified = "openedge.net.http.ihttprequest", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - protected void addUserAgent(final object _p1) - { - object p1 = TypeFactory.initInput(_p1); - - internalProcedure(HttpClient.class, this, "AddUserAgent", new Block((Body) () -> - { - UnimplementedFeature.missing("HttpClient:AddUserAgent METHOD"); + @LegacySignature(type = Type.METHOD, name = "AddUserAgent", parameters = { + @LegacyParameter(name = "p1", type = "OBJECT", qualified = "openedge.net.http.ihttprequest", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + protected void addUserAgent( + final object _p1) + { + object p1 = TypeFactory + .initInput(_p1); + + internalProcedure(HttpClient.class, this, "AddUserAgent", new Block((Body) () -> { + p1.ref().setHeader(HttpHeaderBuilder.build(new character("User-Agent")).ref() + .value(TextOps.substitute("&1/&2 (&3/&4) OpenEdge/&5", clientName, + clientVersion, EnvironmentOps.getOperatingSystem(), + EnvironmentOps.getProcessArchitecture(), EnvironmentOps.getVersion())) + .ref().getHeader()); })); } @@ -218,12 +227,15 @@ * @return logger. */ @LegacySignature(type = Type.GETTER, name = "Logger") - @LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL | RT_LVL_FULL) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_PARTIAL) @Override public object getLogger() { return function(this, "Logger", object.class, new Block((Body) () -> { + if (!logger._isValid()) + logger.assign(ObjectOps.newInstance(VoidLogger.class)); + returnNormal(logger); })); } @@ -265,7 +277,7 @@ object poRequest = TypeFactory.initInput(_poRequest); return function(this, "execute", object.class, new Block((Body) () -> { - object poResponse = ObjectOps.newInstance(HttpResponse.class); + object poResponse = ResponseBuilder.build().ref().getResponse(); execute(poRequest, poResponse); returnNormal(poResponse); })); @@ -306,17 +318,25 @@ object poResponse = TypeFactory.initInput(_poResponse); internalProcedure(this, "__net_http_FwdHttpClientLibrary_constructor__", new Block((Body) () -> { + int retry = Math.max(options.ref().getNumRetries().intValue(), 0); + double retryPause = retry > 0 ? Math.max(options.ref().getPauseBetweenRetry().doubleValue(), 0) : 0; + do { library.ref().execute(poRequest, poResponse); + + if (retry > 0 && retryPause > 0) + LogicalTerminal.pause(retryPause, (String) null); } - while(!processStatusAction(poRequest, poResponse).booleanValue()); + while(retry >= 0 && !processStatusAction(poRequest, poResponse).booleanValue()); })); } /** * Process HttpResponse status code. * + * This basically handle redirects (301, 302, not 307 yet) and authorization required (401). + * * @param poRequest HTTP request. * @param poResponse HTTP Response. */ @@ -331,22 +351,26 @@ { return function(this, "ProcessStatusAction", logical.class, new Block((Body) () -> { - object statusCodeWriter = - TypeFactory.object(IHttpMessageWriter.class); - statusCodeWriter.assign( - StatusCodeWriterBuilder.build(poRequest, poResponse) - ); - if (statusCodeWriter.isValid().booleanValue()) + object statusCodeWriter = StatusCodeWriterBuilder.build(poRequest, poResponse); + + if (statusCodeWriter._isValid()) { + // really no point to retry if authorization is required but not an authenticated request + if (ObjectOps.typeOf(statusCodeWriter, AuthorizationStatusFilter.class).booleanValue() && + ObjectOps.typeOf(poRequest, AuthenticatedRequest.class).booleanValue()) + returnNormal(true); + + // copy session management info from initial response, if any + _copyCookies(poResponse.ref(), poRequest.ref()); + statusCodeWriter.ref().open(); statusCodeWriter.ref().write(poResponse); statusCodeWriter.ref().close(); - poRequest.assign( - ObjectOps.cast(statusCodeWriter.ref().getMessage(), IhttpRequest.class) - ); - returnNormal(new logical(false)); + + returnNormal(false); } - returnNormal(new logical(true)); + + returnNormal(true); })); } @@ -366,24 +390,6 @@ })); } - /** - * Set client name. - * - * @param _pcClientName client name. - */ - @LegacySignature(type = Type.SETTER, name = "ClientName", parameters = - { - @LegacyParameter(name = "pcClientName", type = "CHARACTER", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - void setClientName(final character _pcClientName) - { - character pcClientName = TypeFactory.initInput(_pcClientName); - internalProcedure(this, "ClientName", new Block((Body) () -> - { - this.clientName.assign(pcClientName); - })); - } /** * Get client version. @@ -401,24 +407,6 @@ } /** - * Set client version. - * @param _pcClientVersion client version. - */ - @LegacySignature(type = Type.SETTER, name = "ClientVersion", parameters = - { - @LegacyParameter(name = "pcClientVersion", type = "CHARACTER", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - void setClientVersion(final character _pcClientVersion) - { - character pcClientVersion = TypeFactory.initInput(_pcClientVersion); - internalProcedure(this, "ClientVersion", new Block((Body) () -> - { - this.clientVersion.assign(pcClientVersion); - })); - } - - /** * Get client options. * * @return client options. @@ -433,19 +421,39 @@ returnNormal(this.options); })); } - - @LegacySignature(type = Type.SETTER, name = "Options", parameters = - { - @LegacyParameter(name = "poOptions", type = "OBJECT", - qualified = CLIENTOPTIONS, mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - void setOptions(final object _poOptions) - { - object poOptions = TypeFactory.initInput(_poOptions); - internalProcedure(this, "Options", new Block((Body) () -> + + /** + * Helper method to copy/transfer cookies from one message to another (usually from response to request) + * + * @param source the message to copy cookies from + * @param target the message to copy cookies into + */ + private void _copyCookies(IhttpMessage source, IhttpMessage target) + { + if (source != null & target != null) { - this.options.assign(poOptions); - })); + object oCookies[][] = new object[][] { + TypeFactory.objectExtent(Cookie.class) }; + + source.getCookies(new OutputExtentParameter>() + { + + @Override + public object[] getVariable() + { + return oCookies[0]; + } + + @Override + public void setVariable(object[] reference) + { + oCookies[0] = reference; + } + }); + + // if there are any set those on request + if (oCookies[0].length > 0) + target.setCookies(oCookies[0]); + } } } === modified file 'src/com/goldencode/p2j/oo/net/http/HttpClientDecorator.java' --- src/com/goldencode/p2j/oo/net/http/HttpClientDecorator.java 2020-06-15 00:40:59 +0000 +++ src/com/goldencode/p2j/oo/net/http/HttpClientDecorator.java 2020-11-03 14:06:36 +0000 @@ -7,6 +7,8 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. ** 003 MP 20200603 add constructors and methods like originar class. +** 004 ME 20201023 Implement all methods as pass-through for decorated client. +** 20201103 Fix execute method with only the request parameter. */ /* @@ -85,35 +87,22 @@ * */ @LegacyResource(resource = "OpenEdge.Net.HTTP.HttpClientDecorator") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_PARTIAL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public abstract class HttpClientDecorator extends BaseObject implements IhttpClient { @LegacySignature(type = Type.PROPERTY, name = "DecoratedHttpClient") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) private object decoratedHttpClient = TypeFactory.object(com.goldencode.p2j.oo.net.http.IhttpClient.class); - @LegacySignature(type = Type.PROPERTY, name = "ClientName") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) - private character clientName = TypeFactory.character(); - - @LegacySignature(type = Type.PROPERTY, name = "ClientVersion") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) - private character clientVersion = TypeFactory.character(); - - @LegacySignature(type = Type.PROPERTY, name = "Options") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) - private object options = - TypeFactory.object(com.goldencode.p2j.oo.net.http.ClientOptions.class); - public void __net_http_HttpClientDecorator_execute__() { externalProcedure(HttpClientDecorator.class, HttpClientDecorator.this, new Block((Init) () -> { - ObjectOps.register(options, decoratedHttpClient); + ObjectOps.register(decoratedHttpClient); }, (Body) () -> { @@ -124,7 +113,7 @@ } @LegacySignature(type = Type.GETTER, name = "DecoratedHttpClient") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) protected object getDecoratedHttpClient() { return function(HttpClientDecorator.class, this, "DecoratedHttpClient", object.class, new Block((Body) () -> @@ -134,32 +123,32 @@ } @LegacySignature(type = Type.GETTER, name = "ClientName") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public character getClientName() { return function(HttpClientDecorator.class, this, "ClientName", character.class, new Block((Body) () -> { - returnNormal(clientName); + returnNormal(decoratedHttpClient.ref().getClientName()); })); } @LegacySignature(type = Type.GETTER, name = "ClientVersion") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public character getClientVersion() { return function(HttpClientDecorator.class, this, "ClientVersion", character.class, new Block((Body) () -> { - returnNormal(clientVersion); + returnNormal(decoratedHttpClient.ref().getClientVersion()); })); } @LegacySignature(type = Type.GETTER, name = "Options") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object getOptions() { return function(HttpClientDecorator.class, this, "Options", object.class, new Block((Body) () -> { - returnNormal(options); + returnNormal(decoratedHttpClient.ref().getOptions()); })); } @@ -167,7 +156,7 @@ { @LegacyParameter(name = "poHttpClient", type = "OBJECT", qualified = "openedge.net.http.ihttpclient", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void __net_http_HttpClientDecorator_constructor__(final object _poHttpClient) { object poHttpClient = TypeFactory.initInput(_poHttpClient); @@ -190,15 +179,17 @@ { @LegacyParameter(name = "poRequest", type = "OBJECT", qualified = "openedge.net.http.ihttprequest", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object execute( final object _poRequest) { - object poRequest = TypeFactory.initInput(_poRequest); - return function(HttpClientDecorator.class, this, "Execute", object.class, new Block((Body) () -> { - UnimplementedFeature.missing("HttpClientDecorator:Execute I METHOD"); + object poResponse = ResponseBuilder.build().ref().getResponse(); + + execute(_poRequest, poResponse); + + returnNormal(poResponse); })); } @@ -207,18 +198,12 @@ @LegacyParameter(name = "poRequest", type = "OBJECT", qualified = "openedge.net.http.ihttprequest", mode = "INPUT"), @LegacyParameter(name = "poResponse", type = "OBJECT", qualified = "openedge.net.http.ihttpresponse", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void execute( final object _poRequest, final object _poResponse) { - object poRequest = TypeFactory.initInput(_poRequest); - object poResponse = TypeFactory.initInput(_poResponse); - - internalProcedure(HttpClientDecorator.class, this, "Execute", new Block((Body) () -> - { - UnimplementedFeature.missing("HttpClientDecorator:Execute II METHOD"); - })); + decoratedHttpClient.ref().execute(_poRequest, _poResponse); } } === modified file 'src/com/goldencode/p2j/oo/net/http/HttpHeader.java' --- src/com/goldencode/p2j/oo/net/http/HttpHeader.java 2020-09-29 09:09:19 +0000 +++ src/com/goldencode/p2j/oo/net/http/HttpHeader.java 2021-01-11 07:55:39 +0000 @@ -9,6 +9,8 @@ ** 002 IAS 20190527 Added multipart support. ** 003 CA 20191024 Added method support levels and updated the class support level. ** 004 ME 20200413 Fix parameters and to string methods. +** ME 20201204 Fix strip quotes for value. +** ME 20210111 Fix toString (null header). */ /* @@ -409,12 +411,10 @@ { return function(this, "GetBaseValue", character.class, new Block((Body)() -> { - if (paramDelimiter.getValue().trim().isEmpty()) + if (TextOps.isEmpty(paramDelimiter)) returnNormal(value); - String[] params = TextOps.entries(value.getValue(), paramDelimiter.getValue()); - - returnNormal(new character(params[0])); + returnNormal(TextOps.entry(1, value, paramDelimiter)); })); } @@ -570,16 +570,19 @@ } else { - String p = p1.getValue(); - - if (p.length() > 1 && p.startsWith(QUOTE) && p.endsWith(QUOTE)) - { - p = p.substring(1, p.length() - 2); - } - - this.value.assign(p); - - _extractParameters(); + if (!TextOps.isEmpty(paramDelimiter)) + { + this.value.assign(p1); + _extractParameters(); + } + else + { + String p = p1.getValue(); + + this.value.assign(p.length() > 1 && p.startsWith(QUOTE) && p.endsWith(QUOTE) + ? p.substring(1, p.length() - 1) + : p); + } } })); } @@ -611,15 +614,7 @@ { return function(this, "ToString", character.class, new Block((Body) () -> { - String ret = name.getValue() + ": "; - - if (!value.isUnknown()) - ret += getBaseValue().getValue(); - - if (params.size() > 0) - ret += getParameterValues().getValue(); - - returnNormal(ret); + returnNormal(TextOps.substitute("&1: &2&3", name, getBaseValue(), getParameterValues())); })); } === modified file 'src/com/goldencode/p2j/oo/net/http/HttpMessage.java' --- src/com/goldencode/p2j/oo/net/http/HttpMessage.java 2021-01-13 15:36:44 +0000 +++ src/com/goldencode/p2j/oo/net/http/HttpMessage.java 2021-01-31 10:14:52 +0000 @@ -8,7 +8,8 @@ ** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20191024 Added method support levels and updated the class support level. ** 003 MP 20200603 Added missing methods as stubs taken by converting the skeleton using FWD. -** 004 CA 20210113 Renamed clear() to clear_(), to follow NameConverter's rules. +** 004 ME 20201103 Set cookies array entries only when we have any. +** 005 CA 20210113 Renamed clear() to clear_(), to follow NameConverter's rules. */ /* @@ -621,29 +622,29 @@ * * @return The number of cookies returned. */ - @LegacySignature(type = Type.METHOD, name = "GetCookies", parameters = - { - @LegacyParameter(name = "p1", type = "OBJECT", extent = -1, - qualified = "openedge.net.http.cookie", mode = "OUTPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public integer getCookies(final OutputExtentParameter> extp1) - { - - return function(this, "GetCookies", integer.class, new Block((Body) () -> - { - object[] p1 = extp1.initParameter(this.cookies.ref().getSize().intValue()); - - object valueCollection = cookies.ref().getValues(); - - object[] cookieArray = valueCollection.ref().toArray(); - - for(int i = 0; i < cookieArray.length; i++) + @LegacySignature(type = Type.METHOD, name = "GetCookies", parameters = { + @LegacyParameter(name = "p1", type = "OBJECT", extent = -1, qualified = "openedge.net.http.cookie", mode = "OUTPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + public integer getCookies(final OutputExtentParameter> extpoCookies) + { + + return function(this, "GetCookies", integer.class, new Block((Body) () -> { + object[] cookies = extpoCookies + .initParameter(this.cookies.ref().getSize().intValue()); + + if (cookies.length > 0) { - p1[i] = ObjectOps.cast(cookieArray[i], Cookie.class); + object valueCollection = this.cookies.ref().getValues(); + + object[] cookieArray = valueCollection.ref().toArray(); + + for (int i = 0; i < cookieArray.length; i++) + { + cookies[i] = ObjectOps.cast(cookieArray[i], Cookie.class); + } } - - returnNormal(new integer(p1.length)); + + returnNormal(new integer(cookies.length)); })); } === modified file 'src/com/goldencode/p2j/oo/net/http/HttpRequest.java' --- src/com/goldencode/p2j/oo/net/http/HttpRequest.java 2020-09-13 21:45:15 +0000 +++ src/com/goldencode/p2j/oo/net/http/HttpRequest.java 2020-11-25 07:37:46 +0000 @@ -7,6 +7,8 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. ** 002 MP 20200707 Add code to setHost method +** 003 ME 20201111 Update support level, no-undo variables. +** 20201118 Fix cookies header update on cookies related operations. */ /* @@ -66,15 +68,9 @@ import static com.goldencode.p2j.util.BlockManager.*; -import java.util.Arrays; -import java.util.Map; -import java.util.stream.Collectors; - import static com.goldencode.p2j.report.ReportConstants.*; import com.goldencode.p2j.oo.core.*; -import com.goldencode.p2j.oo.core.collections.IStringKeyedMap; -import com.goldencode.p2j.oo.core.collections.Iiterator; import com.goldencode.p2j.oo.net.*; import com.goldencode.p2j.util.*; import com.goldencode.p2j.util.BlockManager.Action; @@ -87,7 +83,7 @@ * */ @LegacyResource(resource = "OpenEdge.Net.HTTP.HttpRequest") -@LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL|RT_LVL_PARTIAL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class HttpRequest extends com.goldencode.p2j.oo.net.http.HttpMessage implements com.goldencode.p2j.oo.net.http.IhttpRequest @@ -100,14 +96,12 @@ protected static final String NET_HTTP_METHOD_ENUM = "OpenEdge.Net.HTTP.MethodEnum"; /** Request method. */ - private final character method = UndoableFactory.character(); - /** HTTP version */ - private final character version = UndoableFactory.character(); + private final character method = TypeFactory.character(); /** Request URI */ - private final object uri = UndoableFactory.object(Uri.class); + private final object uri = TypeFactory.object(Uri.class); - private character mcMethod = UndoableFactory.character(); - private object moUri = UndoableFactory.object(Uri.class); + private character mcMethod = TypeFactory.character(); + private object moUri = TypeFactory.object(Uri.class); /** * Get the HTTP method. @@ -194,7 +188,8 @@ internalProcedure(HttpRequest.this, "ClearCookies", new Block((Body) () -> { super.clearCookies(); - updateCookieHeader(); + + stripCookieHeader(null); })); } @@ -208,13 +203,21 @@ { @LegacyParameter(name = "pcName", type = CHAR, mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void removeCookie(character _pcName) { + character pcName = TypeFactory.initInput(_pcName); + internalProcedure(HttpRequest.this, "RemoveCookie", new Block((Body) () -> { - super.removeCookie(_pcName); - updateCookieHeader(); + boolean hasCookie = !pcName.isUnknown() && hasCookie(pcName).booleanValue(); + + super.removeCookie(pcName); + + if (hasCookie) + { + stripCookieHeader(pcName);; + } })); } @@ -262,7 +265,7 @@ { @LegacyParameter(name = "poCookie", type = NET_COOKIE, mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void setCookie(object _poCookie) { object poCookie = TypeFactory.initInput(_poCookie); @@ -278,7 +281,12 @@ } else { - updateCookieHeader(); + this.setHeader(HttpHeaderBuilder.build(headerName).ref() + .value(TextOps.substitute("&1=&2", poCookie.ref().getName(), poCookie.ref().getValue())) + .ref() + .parametersDelimitedBy(new character(";")) + .ref() + .getHeader()); } })); } @@ -297,7 +305,8 @@ if(moUri._isValid()) { - this.uri.assign(this.moUri); + setUri(this.moUri); + this.method.assign(this.mcMethod); this.moUri.setUnknown(); this.mcMethod.setUnknown(); @@ -375,31 +384,39 @@ public void __net_http_HttpRequest_constructor__(final object _poMethod, final object _poURI) { + object poMethod = TypeFactory.initInput(_poMethod); + internalProcedure(this, "__net_http_HttpRequest_constructor__", new Block((Body) () -> { - this.__net_http_HttpRequest_constructor__(_poMethod.ref().toLegacyString(), _poURI); + Assert.notNull(poMethod, new character("Method")); + + this.__net_http_HttpRequest_constructor__(poMethod.ref().toLegacyString(), _poURI); })); } - private void updateCookieHeader () { + private void stripCookieHeader (character pcName) { character headerName = new character("Cookie"); - object cookies = super.getCookies(); - - if (cookies.isUnknown() || cookies.ref().isEmpty().booleanValue()) + if (pcName == null) + { this.removeHeader(headerName); - - String headerValue = cookies.ref().getMap().entrySet().stream() - .sorted((a, b) -> a.toString().compareTo(b.toString())) - .map(e -> e.getKey() + "=" + ((Cookie) e.getValue().ref()).getValue().getValue()) - .collect(Collectors.joining(";")); - - this.setHeader(HttpHeaderBuilder.build(headerName).ref() - .value(new character(headerValue)) - .ref() - .parametersDelimitedBy(new character(";")) - .ref() - .getHeader()); - + } + else + { + object header = this.getHeader(headerName); + + if (header._isValid()) + { + if (header.ref().hasParameter(pcName).booleanValue()) + { + header.ref().removeParameters(pcName); + } + else + { + // must be header value + header.ref().setValue(new character("")); + } + } + } } } === modified file 'src/com/goldencode/p2j/oo/net/http/HttpRequestDecorator.java' --- src/com/goldencode/p2j/oo/net/http/HttpRequestDecorator.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/HttpRequestDecorator.java 2020-11-25 07:34:41 +0000 @@ -7,6 +7,8 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. ** 002 MP 20200611 Added missing methods as stubs taken by converting the skeleton using FWD. +** 003 ME 20201105 Set all methods as pass-through to decorated request. +** 20201118 Check if decorated request can be adapted to requested class. */ /* @@ -93,61 +95,23 @@ com.goldencode.p2j.oo.core.IAdaptable { @LegacySignature(type = Type.PROPERTY, name = "DecoratedHttpRequest") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) private object decoratedHttpRequest = TypeFactory.object(com.goldencode.p2j.oo.net.http.IhttpRequest.class); - @LegacySignature(type = Type.PROPERTY, name = "Method") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - private character method = TypeFactory.character(); - - @LegacySignature(type = Type.PROPERTY, name = "URI") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - private object uri = TypeFactory.object(com.goldencode.p2j.oo.net.Uri.class); - - @LegacySignature(type = Type.PROPERTY, name = "Version") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - private character version = TypeFactory.character(); - - @LegacySignature(type = Type.PROPERTY, name = "ContentType") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - private character contentType = TypeFactory.character(); - - @LegacySignature(type = Type.PROPERTY, name = "CharacterEncoding") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - private character characterEncoding = TypeFactory.character(); - - @LegacySignature(type = Type.PROPERTY, name = "ContentMD5") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - private raw contentMd5 = TypeFactory.raw(); - - @LegacySignature(type = Type.PROPERTY, name = "Entity") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - private object entity = TypeFactory.object(com.goldencode.p2j.oo.lang._BaseObject_.class); - - @LegacySignature(type = Type.PROPERTY, name = "ContentLength") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - private integer contentLength = TypeFactory.integer(); - - @LegacySignature(type = Type.PROPERTY, name = "TransferEncoding") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - private character transferEncoding = TypeFactory.character(); - public void __net_http_HttpRequestDecorator_execute__() { externalProcedure(HttpRequestDecorator.class, HttpRequestDecorator.this, new Block((Init) () -> { - ObjectOps.register(entity, uri, decoratedHttpRequest); + ObjectOps.register(decoratedHttpRequest); }, (Body) () -> { onBlockLevel(Condition.ERROR, Action.THROW); - { - } })); } @LegacySignature(type = Type.GETTER, name = "DecoratedHttpRequest") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) protected object getDecoratedHttpRequest() { return function(HttpRequestDecorator.class, this, "DecoratedHttpRequest", object.class, new Block((Body) () -> @@ -157,7 +121,7 @@ } @LegacySignature(type = Type.GETTER, name = "Method") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public character getMethod() { return function(HttpRequestDecorator.class, this, "Method", character.class, new Block((Body) () -> @@ -170,11 +134,9 @@ { @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void setMethod(final character _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void setMethod(final character var) { - character var = TypeFactory.initInput(_var); - internalProcedure(HttpRequestDecorator.class, this, "Method", new Block((Body) () -> { this.decoratedHttpRequest.ref().setMethod(var); @@ -182,12 +144,12 @@ } @LegacySignature(type = Type.GETTER, name = "URI") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public object getUri() { return function(HttpRequestDecorator.class, this, "URI", object.class, new Block((Body) () -> { - returnNormal(this.getDecoratedHttpRequest().ref().getUri()); + returnNormal(this.decoratedHttpRequest.ref().getUri()); })); } @@ -195,11 +157,9 @@ { @LegacyParameter(name = "var", type = "OBJECT", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void setUri(final object _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void setUri(final object var) { - object var = TypeFactory.initInput(_var); - internalProcedure(HttpRequestDecorator.class, this, "URI", new Block((Body) () -> { this.decoratedHttpRequest.ref().setUri(var); @@ -207,7 +167,7 @@ } @LegacySignature(type = Type.GETTER, name = "Version") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public character getVersion() { return function(HttpRequestDecorator.class, this, "Version", character.class, new Block((Body) () -> @@ -220,11 +180,9 @@ { @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void setVersion(final character _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void setVersion(final character var) { - character var = TypeFactory.initInput(_var); - internalProcedure(HttpRequestDecorator.class, this, "Version", new Block((Body) () -> { this.decoratedHttpRequest.ref().setVersion(var); @@ -232,7 +190,7 @@ } @LegacySignature(type = Type.GETTER, name = "ContentType") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public character getContentType() { return function(HttpRequestDecorator.class, this, "ContentType", character.class, new Block((Body) () -> @@ -245,11 +203,9 @@ { @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void setContentType(final character _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void setContentType(final character var) { - character var = TypeFactory.initInput(_var); - internalProcedure(HttpRequestDecorator.class, this, "ContentType", new Block((Body) () -> { this.decoratedHttpRequest.ref().setContentType(var); @@ -257,7 +213,7 @@ } @LegacySignature(type = Type.GETTER, name = "CharacterEncoding") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public character getCharacterEncoding() { return function(HttpRequestDecorator.class, this, "CharacterEncoding", character.class, new Block((Body) () -> @@ -270,11 +226,9 @@ { @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void setCharacterEncoding(final character _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void setCharacterEncoding(final character var) { - character var = TypeFactory.initInput(_var); - internalProcedure(HttpRequestDecorator.class, this, "CharacterEncoding", new Block((Body) () -> { this.decoratedHttpRequest.ref().setCharacterEncoding(var); @@ -282,7 +236,7 @@ } @LegacySignature(type = Type.GETTER, name = "ContentMD5") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public raw getContentMd5() { return function(HttpRequestDecorator.class, this, "ContentMD5", raw.class, new Block((Body) () -> @@ -295,11 +249,9 @@ { @LegacyParameter(name = "var", type = "RAW", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void setContentMd5(final raw _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void setContentMd5(final raw var) { - raw var = TypeFactory.initInput(_var); - internalProcedure(HttpRequestDecorator.class, this, "ContentMD5", new Block((Body) () -> { this.decoratedHttpRequest.ref().setContentMd5(var); @@ -307,7 +259,7 @@ } @LegacySignature(type = Type.GETTER, name = "Entity") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public object getEntity() { return function(HttpRequestDecorator.class, this, "Entity", object.class, new Block((Body) () -> @@ -320,11 +272,9 @@ { @LegacyParameter(name = "var", type = "OBJECT", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void setEntity(final object _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void setEntity(final object var) { - object var = TypeFactory.initInput(_var); - internalProcedure(HttpRequestDecorator.class, this, "Entity", new Block((Body) () -> { this.decoratedHttpRequest.ref().setEntity(var); @@ -332,7 +282,7 @@ } @LegacySignature(type = Type.GETTER, name = "ContentLength") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public integer getContentLength() { return function(HttpRequestDecorator.class, this, "ContentLength", integer.class, new Block((Body) () -> @@ -345,11 +295,9 @@ { @LegacyParameter(name = "var", type = "INTEGER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void setContentLength(final integer _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void setContentLength(final integer var) { - integer var = TypeFactory.initInput(_var); - internalProcedure(HttpRequestDecorator.class, this, "ContentLength", new Block((Body) () -> { this.decoratedHttpRequest.ref().setContentLength(var); @@ -357,7 +305,7 @@ } @LegacySignature(type = Type.GETTER, name = "TransferEncoding") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public character getTransferEncoding() { return function(HttpRequestDecorator.class, this, "TransferEncoding", character.class, new Block((Body) () -> @@ -370,11 +318,9 @@ { @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void setTransferEncoding(final character _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void setTransferEncoding(final character var) { - character var = TypeFactory.initInput(_var); - internalProcedure(HttpRequestDecorator.class, this, "TransferEncoding", new Block((Body) () -> { this.decoratedHttpRequest.ref().setTransferEncoding(var); @@ -385,7 +331,7 @@ { @LegacyParameter(name = "poHttpRequest", type = "OBJECT", qualified = "openedge.net.http.ihttprequest", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_http_HttpRequestDecorator_constructor__(final object _poHttpRequest) { object poHttpRequest = TypeFactory.initInput(_poHttpRequest); @@ -406,11 +352,9 @@ { @LegacyParameter(name = "poHeader", type = "OBJECT", qualified = "openedge.net.http.httpheader", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void setHeader(final object _poHeader) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void setHeader(final object poHeader) { - object poHeader = TypeFactory.initInput(_poHeader); - internalProcedure(HttpRequestDecorator.class, this, "SetHeader", new Block((Body) () -> { this.decoratedHttpRequest.ref().setHeader(poHeader); @@ -419,19 +363,14 @@ @LegacySignature(type = Type.METHOD, name = "SetHeaders", parameters = { - @LegacyParameter(name = "poHeader", type = "OBJECT", extent = -1, qualified = "openedge.net.http.httpheader", mode = "INPUT") + @LegacyParameter(name = "poHeaders", type = "OBJECT", extent = -1, qualified = "openedge.net.http.httpheader", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void setHeaders(final object[] _poHeader) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void setHeaders(final object[] poHeaders) { - object[] poHeader[] = new object[][] - { - TypeFactory.initInput(_poHeader) - }; - internalProcedure(HttpRequestDecorator.class, this, "SetHeaders", new Block((Body) () -> { - UnimplementedFeature.missing("HttpRequestDecorator:SetHeaders METHOD"); + this.decoratedHttpRequest.ref().setHeaders(poHeaders); })); } @@ -439,11 +378,9 @@ { @LegacyParameter(name = "pcName", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public object getHeader(final character _pcName) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public object getHeader(final character pcName) { - character pcName = TypeFactory.initInput(_pcName); - return function(HttpRequestDecorator.class, this, "GetHeader", object.class, new Block((Body) () -> { returnNormal(this.decoratedHttpRequest.ref().getHeader(pcName)); @@ -452,19 +389,14 @@ @LegacySignature(type = Type.METHOD, name = "GetHeaders", parameters = { - @LegacyParameter(name = "poHeader", type = "OBJECT", extent = -1, qualified = "openedge.net.http.httpheader", mode = "OUTPUT") + @LegacyParameter(name = "extpoHeader", type = "OBJECT", extent = -1, qualified = "openedge.net.http.httpheader", mode = "OUTPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public integer getHeaders(final OutputExtentParameter> extpoHeader) { - object[] poHeader[] = new object[][] - { - TypeFactory.initOutput(extpoHeader) - }; - return function(HttpRequestDecorator.class, this, "GetHeaders", integer.class, new Block((Body) () -> { - UnimplementedFeature.missing("HttpRequestDecorator:GetHeaders METHOD"); + returnNormal(this.decoratedHttpRequest.ref().getHeaders(extpoHeader)); })); } @@ -472,7 +404,7 @@ { @LegacyParameter(name = "pcName", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void removeHeader(final character _pcName) { character pcName = TypeFactory.initInput(_pcName); @@ -487,11 +419,9 @@ { @LegacyParameter(name = "pcName", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public logical hasHeader(final character _pcName) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public logical hasHeader(final character pcName) { - character pcName = TypeFactory.initInput(_pcName); - return function(HttpRequestDecorator.class, this, "HasHeader", logical.class, new Block((Body) () -> { returnNormal(this.decoratedHttpRequest.ref().hasHeader(pcName)); @@ -499,7 +429,7 @@ } @LegacySignature(type = Type.METHOD, name = "ClearHeaders") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void clearHeaders() { internalProcedure(HttpRequestDecorator.class, this, "ClearHeaders", new Block((Body) () -> @@ -512,11 +442,9 @@ { @LegacyParameter(name = "poCookie", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void setCookie(final object _poCookie) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void setCookie(final object poCookie) { - object poCookie = TypeFactory.initInput(_poCookie); - internalProcedure(HttpRequestDecorator.class, this, "SetCookie", new Block((Body) () -> { this.decoratedHttpRequest.ref().setCookie(poCookie); @@ -527,35 +455,25 @@ { @LegacyParameter(name = "poCookies", type = "OBJECT", extent = -1, qualified = "openedge.net.http.cookie", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void setCookies(final object[] _poCookies) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void setCookies(final object[] poCookies) { - object[] poCookies[] = new object[][] - { - TypeFactory.initInput(_poCookies) - }; - internalProcedure(HttpRequestDecorator.class, this, "SetCookies", new Block((Body) () -> { - UnimplementedFeature.missing("HttpRequestDecorator:SetCookies METHOD"); + this.decoratedHttpRequest.ref().setCookies(poCookies); })); } @LegacySignature(type = Type.METHOD, name = "GetCookies", parameters = { - @LegacyParameter(name = "poCookies", type = "OBJECT", extent = -1, qualified = "openedge.net.http.cookie", mode = "OUTPUT") + @LegacyParameter(name = "extpoCookies", type = "OBJECT", extent = -1, qualified = "openedge.net.http.cookie", mode = "OUTPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public integer getCookies(final OutputExtentParameter> extpoCookies) { - object[] poCookies[] = new object[][] - { - TypeFactory.initOutput(extpoCookies) - }; - return function(HttpRequestDecorator.class, this, "GetCookies", integer.class, new Block((Body) () -> { - UnimplementedFeature.missing("HttpRequestDecorator:GetCookies METHOD"); + returnNormal(this.decoratedHttpRequest.ref().getCookies(extpoCookies)); })); } @@ -563,11 +481,9 @@ { @LegacyParameter(name = "poCookie", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void removeCookie(final object _poCookie) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void removeCookie(final object poCookie) { - object poCookie = TypeFactory.initInput(_poCookie); - internalProcedure(HttpRequestDecorator.class, this, "RemoveCookie", new Block((Body) () -> { this.decoratedHttpRequest.ref().removeCookie(poCookie); @@ -578,11 +494,9 @@ { @LegacyParameter(name = "poCookie", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public logical hasCookie(final object _poCookie) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public logical hasCookie(final object poCookie) { - object poCookie = TypeFactory.initInput(_poCookie); - return function(HttpRequestDecorator.class, this, "HasCookie", logical.class, new Block((Body) () -> { returnNormal(this.decoratedHttpRequest.ref().hasCookie(poCookie)); @@ -590,7 +504,7 @@ } @LegacySignature(type = Type.METHOD, name = "ClearCookies") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void clearCookies() { internalProcedure(HttpRequestDecorator.class, this, "ClearCookies", new Block((Body) () -> @@ -603,11 +517,9 @@ { @LegacyParameter(name = "pcName", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void removeCookie(final character _pcName) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void removeCookie(final character pcName) { - character pcName = TypeFactory.initInput(_pcName); - internalProcedure(HttpRequestDecorator.class, this, "RemoveCookie", new Block((Body) () -> { this.decoratedHttpRequest.ref().removeCookie(pcName); @@ -618,11 +530,9 @@ { @LegacyParameter(name = "pcName", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public logical hasCookie(final character _pcName) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public logical hasCookie(final character pcName) { - character pcName = TypeFactory.initInput(_pcName); - return function(HttpRequestDecorator.class, this, "HasCookie", logical.class, new Block((Body) () -> { returnNormal(this.decoratedHttpRequest.ref().hasCookie(pcName)); @@ -633,11 +543,9 @@ { @LegacyParameter(name = "pcName", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public object getCookie(final character _pcName) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public object getCookie(final character pcName) { - character pcName = TypeFactory.initInput(_pcName); - return function(HttpRequestDecorator.class, this, "GetCookie", object.class, new Block((Body) () -> { returnNormal(this.decoratedHttpRequest.ref().getCookie(pcName)); @@ -648,26 +556,22 @@ { @LegacyParameter(name = "poAdaptTo", type = "OBJECT", qualified = "progress.lang.class", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public object getAdapter(final object _poAdaptTo) { object poAdaptTo = TypeFactory.initInput(_poAdaptTo); return function(HttpRequestDecorator.class, this, "GetAdapter", object.class, new Block((Body) () -> { - Assert.notNull(_poAdaptTo, new character("Adapter")); + Assert.notNull(poAdaptTo, new character("Adapter")); - if(this.getLegacyClass().ref()._isA(poAdaptTo)) - { + if (getLegacyClass().ref()._isA(poAdaptTo)) returnNormal(ObjectOps.thisObject()); - } - - if(this.decoratedHttpRequest._isValid() && this.decoratedHttpRequest instanceof IAdaptable) - { - returnNormal(((IAdaptable) this.decoratedHttpRequest.ref()).getAdapter(poAdaptTo)); - } - - returnNormal(new unknown()); + + if (ObjectOps.typeOf(decoratedHttpRequest, IAdaptable.class).booleanValue()) + returnNormal(ObjectOps.cast(decoratedHttpRequest, IAdaptable.class).ref().getAdapter(poAdaptTo)); + + returnNormal(new object()); })); } } === modified file 'src/com/goldencode/p2j/oo/net/http/HttpRequestError.java' --- src/com/goldencode/p2j/oo/net/http/HttpRequestError.java 2020-06-15 00:40:59 +0000 +++ src/com/goldencode/p2j/oo/net/http/HttpRequestError.java 2020-12-17 07:29:53 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 MP 20200603 First version, stubs taken by converting the skeleton using FWD. +** 002 ME 20201214 Implement as of OE12.2. ** */ @@ -68,17 +69,19 @@ import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; -import static com.goldencode.p2j.report.ReportConstants.CVT_LVL_FULL; -import static com.goldencode.p2j.report.ReportConstants.RT_LVL_STUB; +import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.*; import static com.goldencode.p2j.util.InternalEntry.Type; +import com.goldencode.p2j.oo.core.system.ApplicationError; +import com.goldencode.p2j.oo.lang.LegacyClass; + /** * Business logic (converted to Java from the 4GL source code * in OpenEdge/Net/HTTP/HttpRequestError.cls). */ @LegacyResource(resource = "OpenEdge.Net.HTTP.HttpRequestError") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class HttpRequestError extends com.goldencode.p2j.oo.core.system.ApplicationError { @@ -93,31 +96,32 @@ } @LegacySignature(type = Type.CONSTRUCTOR) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public static void __net_http_HttpRequestError_constructor__static__() { - externalProcedure(HttpRequestError.class, new Block((Body) () -> - { + externalProcedure(HttpRequestError.class, new Block((Body) () -> { onBlockLevel(Condition.ERROR, Action.THROW); + ApplicationError.addError(new object(ObjectOps.getClassInstance(HttpRequestError.class)), + new character("Http Request Error: status &1"), + new longchar("Status code &1 for &2 operation at URI &3")); })); } - + @LegacySignature(type = Type.CONSTRUCTOR, parameters = { @LegacyParameter(name = "pcStatusCode", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "pcMethod", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "pcURI", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void __net_http_HttpRequestError_constructor__(final character _pcStatusCode, final character _pcMethod, final character _pcUri) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void __net_http_HttpRequestError_constructor__(final character pcStatusCode, final character pcMethod, final character pcUri) { - character pcStatusCode = TypeFactory.initInput(_pcStatusCode); - character pcMethod = TypeFactory.initInput(_pcMethod); - character pcUri = TypeFactory.initInput(_pcUri); - internalProcedure(HttpRequestError.class, this, "__net_http_HttpRequestError_constructor__", new Block((Body) () -> { __core_system_ApplicationError_constructor__(); + addMessage(pcStatusCode, new integer(1)); + addMessage(pcMethod, new integer(2)); + addMessage(pcUri, new integer(1)); })); } @@ -128,21 +132,15 @@ @LegacyParameter(name = "pcMethod", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "pcURI", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public void __net_http_HttpRequestError_constructor__(final object _poInnerError, final character _pcStatusCode, final character _pcMethod, final character _pcUri) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void __net_http_HttpRequestError_constructor__(final object poInnerError, final character pcStatusCode, final character pcMethod, final character pcUri) { - object poInnerError = TypeFactory.initInput(_poInnerError); - character pcStatusCode = TypeFactory.initInput(_pcStatusCode); - character pcMethod = TypeFactory.initInput(_pcMethod); - character pcUri = TypeFactory.initInput(_pcUri); - - internalProcedure(HttpRequestError.class, this, "__net_http_HttpRequestError_constructor__", new Block((Init) () -> - { - ObjectOps.register(poInnerError); - }, - (Body) () -> - { - __core_system_ApplicationError_constructor__(); + internalProcedure(HttpRequestError.class, this, "__net_http_HttpRequestError_constructor__", new Block((Body) () -> + { + __core_system_ApplicationError_constructor__(poInnerError); + addMessage(pcStatusCode, new integer(1)); + addMessage(pcMethod, new integer(2)); + addMessage(pcUri, new integer(1)); })); } } === modified file 'src/com/goldencode/p2j/oo/net/http/HttpResponse.java' --- src/com/goldencode/p2j/oo/net/http/HttpResponse.java 2019-10-24 23:19:26 +0000 +++ src/com/goldencode/p2j/oo/net/http/HttpResponse.java 2020-11-23 07:05:51 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20191024 Added method support levels and updated the class support level. +** 003 ME 20201123 Assert non negative status code when set. */ /* @@ -65,7 +66,9 @@ package com.goldencode.p2j.oo.net.http; import com.goldencode.p2j.util.*; -import com.goldencode.p2j.oo.lang.*; +import com.goldencode.p2j.util.BlockManager.Action; +import com.goldencode.p2j.util.BlockManager.Condition; +import com.goldencode.p2j.oo.core.Assert; import static com.goldencode.p2j.util.BlockManager.*; import static com.goldencode.p2j.report.ReportConstants.*; @@ -82,10 +85,10 @@ implements com.goldencode.p2j.oo.net.http.IhttpResponse { /** Response status code */ - private integer statusCode = UndoableFactory.integer(); + private integer statusCode = TypeFactory.integer(); /** Response status reason */ - private character statusReason = UndoableFactory.character(); + private character statusReason = TypeFactory.character(); /** * Execute method. @@ -94,8 +97,7 @@ { externalProcedure(HttpResponse.this, new Block((Body) () -> { - { - } + onBlockLevel(Condition.ERROR, Action.THROW); })); } @@ -128,6 +130,8 @@ internalProcedure(this, "StatusCode", new Block((Body) () -> { + Assert.isZeroOrPositive(var, new character("Status Code")); + statusCode.assign(var); })); } === modified file 'src/com/goldencode/p2j/oo/net/http/HttpResponseDecorator.java' --- src/com/goldencode/p2j/oo/net/http/HttpResponseDecorator.java 2020-05-11 17:44:12 +0000 +++ src/com/goldencode/p2j/oo/net/http/HttpResponseDecorator.java 2020-11-25 07:33:12 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 ME 20200511 First version. +** 20201123 Implement all methods as pass-through. */ /* @@ -63,12 +64,13 @@ package com.goldencode.p2j.oo.net.http; import com.goldencode.p2j.util.*; +import com.goldencode.p2j.util.BlockManager.Action; +import com.goldencode.p2j.util.BlockManager.Condition; import com.goldencode.p2j.oo.net.http.IhttpResponse; +import com.goldencode.p2j.oo.core.Assert; import com.goldencode.p2j.oo.core.IAdaptable; import com.goldencode.p2j.oo.lang.*; import com.goldencode.p2j.oo.lang._BaseObject_; -import com.goldencode.p2j.oo.net.http.HttpHeader; -import com.goldencode.p2j.oo.net.http.Cookie; import com.goldencode.p2j.oo.lang.LegacyClass; import static com.goldencode.p2j.report.ReportConstants.*; @@ -80,52 +82,21 @@ * in OpenEdge/Net/HTTP/HttpResponseDecorator.cls). */ @LegacyResource(resource = "OpenEdge.Net.HTTP.HttpResponseDecorator") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_PARTIAL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class HttpResponseDecorator extends BaseObject implements IhttpResponse, IAdaptable { @LegacySignature(type = Type.PROPERTY, name = "DecoratedHttpResponse") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) private object decoratedHttpResponse = TypeFactory.object(IhttpResponse.class); - @LegacySignature(type = Type.PROPERTY, name = "StatusCode") - private integer statusCode = TypeFactory.integer(); - - @LegacySignature(type = Type.PROPERTY, name = "StatusReason") - private character statusReason = TypeFactory.character(); - - @LegacySignature(type = Type.PROPERTY, name = "Version") - private character version = TypeFactory.character(); - - @LegacySignature(type = Type.PROPERTY, name = "ContentType") - private character contentType = TypeFactory.character(); - - @LegacySignature(type = Type.PROPERTY, name = "CharacterEncoding") - private character characterEncoding = TypeFactory.character(); - - @LegacySignature(type = Type.PROPERTY, name = "ContentMD5") - private raw contentMd5 = TypeFactory.raw(); - - @LegacySignature(type = Type.PROPERTY, name = "Entity") - private object entity = TypeFactory.object(_BaseObject_.class); - - @LegacySignature(type = Type.PROPERTY, name = "ContentLength") - private integer contentLength = TypeFactory.integer(); - - @LegacySignature(type = Type.PROPERTY, name = "TransferEncoding") - private character transferEncoding = TypeFactory.character(); - public void __net_http_HttpResponseDecorator_execute__() { - externalProcedure(HttpResponseDecorator.class, HttpResponseDecorator.this, new Block((Init) () -> - { - ObjectOps.register(entity, decoratedHttpResponse); - }, - (Body) () -> - { - { - } + externalProcedure(HttpResponseDecorator.class, HttpResponseDecorator.this, new Block((Body) () -> + { + onBlockLevel(Condition.ERROR, Action.THROW); })); } @@ -139,11 +110,12 @@ } @LegacySignature(type = Type.GETTER, name = "StatusCode") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public integer getStatusCode() { return function(HttpResponseDecorator.class, this, "StatusCode", integer.class, new Block((Body) () -> { - returnNormal(statusCode); + returnNormal(decoratedHttpResponse.ref().getStatusCode()); })); } @@ -151,22 +123,22 @@ { @LegacyParameter(name = "var", type = "INTEGER", mode = "INPUT") }) - public void setStatusCode(final integer _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void setStatusCode(final integer var) { - integer var = TypeFactory.initInput(_var); - internalProcedure(HttpResponseDecorator.class, this, "StatusCode", new Block((Body) () -> { - statusCode.assign(var); + decoratedHttpResponse.ref().setStatusCode(var); })); } @LegacySignature(type = Type.GETTER, name = "StatusReason") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public character getStatusReason() { return function(HttpResponseDecorator.class, this, "StatusReason", character.class, new Block((Body) () -> { - returnNormal(statusReason); + returnNormal(decoratedHttpResponse.ref().getStatusReason()); })); } @@ -174,22 +146,22 @@ { @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") }) - public void setStatusReason(final character _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void setStatusReason(final character var) { - character var = TypeFactory.initInput(_var); - internalProcedure(HttpResponseDecorator.class, this, "StatusReason", new Block((Body) () -> { - statusReason.assign(var); + decoratedHttpResponse.ref().setStatusReason(var); })); } @LegacySignature(type = Type.GETTER, name = "Version") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public character getVersion() { return function(HttpResponseDecorator.class, this, "Version", character.class, new Block((Body) () -> { - returnNormal(version); + returnNormal(decoratedHttpResponse.ref().getVersion()); })); } @@ -197,22 +169,22 @@ { @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") }) - public void setVersion(final character _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void setVersion(final character var) { - character var = TypeFactory.initInput(_var); - internalProcedure(HttpResponseDecorator.class, this, "Version", new Block((Body) () -> { - version.assign(var); + decoratedHttpResponse.ref().setVersion(var); })); } @LegacySignature(type = Type.GETTER, name = "ContentType") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public character getContentType() { return function(HttpResponseDecorator.class, this, "ContentType", character.class, new Block((Body) () -> { - returnNormal(contentType); + returnNormal(decoratedHttpResponse.ref().getContentType()); })); } @@ -220,22 +192,22 @@ { @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") }) - public void setContentType(final character _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void setContentType(final character var) { - character var = TypeFactory.initInput(_var); - internalProcedure(HttpResponseDecorator.class, this, "ContentType", new Block((Body) () -> { - contentType.assign(var); + decoratedHttpResponse.ref().setContentType(var); })); } @LegacySignature(type = Type.GETTER, name = "CharacterEncoding") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public character getCharacterEncoding() { return function(HttpResponseDecorator.class, this, "CharacterEncoding", character.class, new Block((Body) () -> { - returnNormal(characterEncoding); + returnNormal(decoratedHttpResponse.ref().getCharacterEncoding()); })); } @@ -243,22 +215,22 @@ { @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") }) - public void setCharacterEncoding(final character _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void setCharacterEncoding(final character var) { - character var = TypeFactory.initInput(_var); - internalProcedure(HttpResponseDecorator.class, this, "CharacterEncoding", new Block((Body) () -> { - characterEncoding.assign(var); + decoratedHttpResponse.ref().setCharacterEncoding(var); })); } @LegacySignature(type = Type.GETTER, name = "ContentMD5") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public raw getContentMd5() { return function(HttpResponseDecorator.class, this, "ContentMD5", raw.class, new Block((Body) () -> { - returnNormal(contentMd5); + returnNormal(decoratedHttpResponse.ref().getContentMd5()); })); } @@ -266,22 +238,22 @@ { @LegacyParameter(name = "var", type = "RAW", mode = "INPUT") }) - public void setContentMd5(final raw _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void setContentMd5(final raw var) { - raw var = TypeFactory.initInput(_var); - internalProcedure(HttpResponseDecorator.class, this, "ContentMD5", new Block((Body) () -> { - contentMd5.assign(var); + decoratedHttpResponse.ref().setContentMd5(var); })); } @LegacySignature(type = Type.GETTER, name = "Entity") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object getEntity() { return function(HttpResponseDecorator.class, this, "Entity", object.class, new Block((Body) () -> { - returnNormal(entity); + returnNormal(decoratedHttpResponse.ref().getEntity()); })); } @@ -289,22 +261,22 @@ { @LegacyParameter(name = "var", type = "OBJECT", mode = "INPUT") }) - public void setEntity(final object _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void setEntity(final object var) { - object var = TypeFactory.initInput(_var); - internalProcedure(HttpResponseDecorator.class, this, "Entity", new Block((Body) () -> { - entity.assign(var); + decoratedHttpResponse.ref().setEntity(var); })); } @LegacySignature(type = Type.GETTER, name = "ContentLength") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public integer getContentLength() { return function(HttpResponseDecorator.class, this, "ContentLength", integer.class, new Block((Body) () -> { - returnNormal(contentLength); + returnNormal(decoratedHttpResponse.ref().getContentLength()); })); } @@ -312,22 +284,22 @@ { @LegacyParameter(name = "var", type = "INTEGER", mode = "INPUT") }) - public void setContentLength(final integer _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void setContentLength(final integer var) { - integer var = TypeFactory.initInput(_var); - internalProcedure(HttpResponseDecorator.class, this, "ContentLength", new Block((Body) () -> { - contentLength.assign(var); + decoratedHttpResponse.ref().setContentLength(var); })); } @LegacySignature(type = Type.GETTER, name = "TransferEncoding") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public character getTransferEncoding() { return function(HttpResponseDecorator.class, this, "TransferEncoding", character.class, new Block((Body) () -> { - returnNormal(transferEncoding); + returnNormal(decoratedHttpResponse.ref().getTransferEncoding()); })); } @@ -335,13 +307,12 @@ { @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") }) - public void setTransferEncoding(final character _var) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void setTransferEncoding(final character var) { - character var = TypeFactory.initInput(_var); - internalProcedure(HttpResponseDecorator.class, this, "TransferEncoding", new Block((Body) () -> { - transferEncoding.assign(var); + decoratedHttpResponse.ref().setTransferEncoding(var); })); } @@ -349,6 +320,7 @@ { @LegacyParameter(name = "poHttpResponse", type = "OBJECT", qualified = "openedge.net.http.ihttpresponse", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void __net_http_HttpResponseDecorator_constructor__(final object _poHttpResponse) { object poHttpResponse = TypeFactory.initInput(_poHttpResponse); @@ -360,6 +332,10 @@ (Body) () -> { __lang_BaseObject_constructor__(); + + Assert.notNull(poHttpResponse, new character("HttpResponse")); + + decoratedHttpResponse.assign(poHttpResponse); })); } @@ -367,188 +343,207 @@ { @LegacyParameter(name = "poHeader", type = "OBJECT", qualified = "openedge.net.http.httpheader", mode = "INPUT") }) - public void setHeader(final object _poHeader) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void setHeader(final object poHeader) { - object poHeader = TypeFactory.initInput(_poHeader); - - internalProcedure(HttpResponseDecorator.class, this, "SetHeader", new Block()); + internalProcedure(HttpResponseDecorator.class, this, "SetHeader", new Block((Body) () -> { + decoratedHttpResponse.ref().setHeader(poHeader); + })); } @LegacySignature(type = Type.METHOD, name = "SetHeaders", parameters = { - @LegacyParameter(name = "poHeader", type = "OBJECT", extent = -1, qualified = "openedge.net.http.httpheader", mode = "INPUT") + @LegacyParameter(name = "poHeaders", type = "OBJECT", extent = -1, qualified = "openedge.net.http.httpheader", mode = "INPUT") }) - public void setHeaders(final object[] _poHeader) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void setHeaders(final object[] poHeaders) { - object[] poHeader[] = new object[][] - { - TypeFactory.initInput(_poHeader) - }; - - internalProcedure(HttpResponseDecorator.class, this, "SetHeaders", new Block()); + internalProcedure(HttpResponseDecorator.class, this, "SetHeaders", new Block((Body) () -> { + decoratedHttpResponse.ref().setHeaders(poHeaders); + })); } @LegacySignature(type = Type.METHOD, name = "GetHeader", qualified = "openedge.net.http.httpheader", parameters = { @LegacyParameter(name = "pcName", type = "CHARACTER", mode = "INPUT") }) - public object getHeader(final character _pcName) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public object getHeader(final character pcName) { - character pcName = TypeFactory.initInput(_pcName); - - return function(HttpResponseDecorator.class, this, "GetHeader", object.class, new Block()); + return function(HttpResponseDecorator.class, this, "GetHeader", object.class, new Block((Body) () -> { + returnNormal(decoratedHttpResponse.ref().getHeader(pcName)); + })); } @LegacySignature(type = Type.METHOD, name = "GetHeaders", parameters = { - @LegacyParameter(name = "poHeader", type = "OBJECT", extent = -1, qualified = "openedge.net.http.httpheader", mode = "OUTPUT") + @LegacyParameter(name = "extpoHeader", type = "OBJECT", extent = -1, qualified = "openedge.net.http.httpheader", mode = "OUTPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public integer getHeaders(final OutputExtentParameter> extpoHeader) { - object[] poHeader[] = new object[][] - { - TypeFactory.initOutput(extpoHeader) - }; - - return function(HttpResponseDecorator.class, this, "GetHeaders", integer.class, new Block()); + return function(HttpResponseDecorator.class, this, "GetHeaders", integer.class, new Block((Body) () -> { + returnNormal(decoratedHttpResponse.ref().getHeaders(extpoHeader)); + })); } @LegacySignature(type = Type.METHOD, name = "RemoveHeader", parameters = { @LegacyParameter(name = "pcName", type = "CHARACTER", mode = "INPUT") }) - public void removeHeader(final character _pcName) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void removeHeader(final character pcName) { - character pcName = TypeFactory.initInput(_pcName); - - internalProcedure(HttpResponseDecorator.class, this, "RemoveHeader", new Block()); + internalProcedure(HttpResponseDecorator.class, this, "RemoveHeader", new Block((Body) () -> { + decoratedHttpResponse.ref().removeHeader(pcName); + })); } @LegacySignature(type = Type.METHOD, name = "HasHeader", parameters = { @LegacyParameter(name = "pcName", type = "CHARACTER", mode = "INPUT") }) - public logical hasHeader(final character _pcName) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public logical hasHeader(final character pcName) { - character pcName = TypeFactory.initInput(_pcName); - - return function(HttpResponseDecorator.class, this, "HasHeader", logical.class, new Block()); + return function(HttpResponseDecorator.class, this, "HasHeader", logical.class, new Block((Body) () -> { + returnNormal(decoratedHttpResponse.ref().hasHeader(pcName)); + })); } @LegacySignature(type = Type.METHOD, name = "ClearHeaders") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void clearHeaders() { - internalProcedure(HttpResponseDecorator.class, this, "ClearHeaders", new Block()); + internalProcedure(HttpResponseDecorator.class, this, "ClearHeaders", new Block((Body) () -> { + decoratedHttpResponse.ref().clearHeaders(); + })); } @LegacySignature(type = Type.METHOD, name = "SetCookie", parameters = { @LegacyParameter(name = "poCookie", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") }) - public void setCookie(final object _poCookie) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void setCookie(final object poCookie) { - object poCookie = TypeFactory.initInput(_poCookie); - - internalProcedure(HttpResponseDecorator.class, this, "SetCookie", new Block()); + internalProcedure(HttpResponseDecorator.class, this, "SetCookie", new Block((Body) () -> { + decoratedHttpResponse.ref().setCookie(poCookie); + })); } @LegacySignature(type = Type.METHOD, name = "SetCookies", parameters = { @LegacyParameter(name = "poCookies", type = "OBJECT", extent = -1, qualified = "openedge.net.http.cookie", mode = "INPUT") }) - public void setCookies(final object[] _poCookies) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void setCookies(final object[] poCookies) { - object[] poCookies[] = new object[][] - { - TypeFactory.initInput(_poCookies) - }; - - internalProcedure(HttpResponseDecorator.class, this, "SetCookies", new Block()); + internalProcedure(HttpResponseDecorator.class, this, "SetCookies", new Block((Body) () -> { + decoratedHttpResponse.ref().setCookies(poCookies); + })); } @LegacySignature(type = Type.METHOD, name = "GetCookies", parameters = { - @LegacyParameter(name = "poCookies", type = "OBJECT", extent = -1, qualified = "openedge.net.http.cookie", mode = "OUTPUT") + @LegacyParameter(name = "extpoCookies", type = "OBJECT", extent = -1, qualified = "openedge.net.http.cookie", mode = "OUTPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public integer getCookies(final OutputExtentParameter> extpoCookies) { - object[] poCookies[] = new object[][] - { - TypeFactory.initOutput(extpoCookies) - }; - - return function(HttpResponseDecorator.class, this, "GetCookies", integer.class, new Block()); + return function(HttpResponseDecorator.class, this, "GetCookies", integer.class, new Block((Body) () -> { + returnNormal(decoratedHttpResponse.ref().getCookies(extpoCookies)); + })); } @LegacySignature(type = Type.METHOD, name = "RemoveCookie", parameters = { @LegacyParameter(name = "poCookie", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") }) - public void removeCookie(final object _poCookie) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void removeCookie(final object poCookie) { - object poCookie = TypeFactory.initInput(_poCookie); - - internalProcedure(HttpResponseDecorator.class, this, "RemoveCookie", new Block()); + internalProcedure(HttpResponseDecorator.class, this, "RemoveCookie", new Block((Body) () -> { + decoratedHttpResponse.ref().removeCookie(poCookie); + })); } @LegacySignature(type = Type.METHOD, name = "HasCookie", parameters = { @LegacyParameter(name = "poCookie", type = "OBJECT", qualified = "openedge.net.http.cookie", mode = "INPUT") }) - public logical hasCookie(final object _poCookie) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public logical hasCookie(final object poCookie) { - object poCookie = TypeFactory.initInput(_poCookie); - - return function(HttpResponseDecorator.class, this, "HasCookie", logical.class, new Block()); + return function(HttpResponseDecorator.class, this, "HasCookie", logical.class, new Block((Body) () -> { + returnNormal(decoratedHttpResponse.ref().hasCookie(poCookie)); + })); } @LegacySignature(type = Type.METHOD, name = "ClearCookies") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void clearCookies() { - internalProcedure(HttpResponseDecorator.class, this, "ClearCookies", new Block()); + internalProcedure(HttpResponseDecorator.class, this, "ClearCookies", new Block((Body) () -> { + decoratedHttpResponse.ref().clearCookies(); + })); } @LegacySignature(type = Type.METHOD, name = "RemoveCookie", parameters = { @LegacyParameter(name = "pcName", type = "CHARACTER", mode = "INPUT") }) - public void removeCookie(final character _pcName) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void removeCookie(final character pcName) { - character pcName = TypeFactory.initInput(_pcName); - - internalProcedure(HttpResponseDecorator.class, this, "RemoveCookie", new Block()); + internalProcedure(HttpResponseDecorator.class, this, "RemoveCookie", new Block((Body) () -> { + decoratedHttpResponse.ref().removeCookie(pcName); + })); } @LegacySignature(type = Type.METHOD, name = "HasCookie", parameters = { @LegacyParameter(name = "pcName", type = "CHARACTER", mode = "INPUT") }) - public logical hasCookie(final character _pcName) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public logical hasCookie(final character pcName) { - character pcName = TypeFactory.initInput(_pcName); - - return function(HttpResponseDecorator.class, this, "HasCookie", logical.class, new Block()); + return function(HttpResponseDecorator.class, this, "HasCookie", logical.class, new Block((Body) () -> { + returnNormal(decoratedHttpResponse.ref().hasCookie(pcName)); + })); } @LegacySignature(type = Type.METHOD, name = "GetCookie", qualified = "openedge.net.http.cookie", parameters = { @LegacyParameter(name = "pcName", type = "CHARACTER", mode = "INPUT") }) - public object getCookie(final character _pcName) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public object getCookie(final character pcName) { - character pcName = TypeFactory.initInput(_pcName); - - return function(HttpResponseDecorator.class, this, "GetCookie", object.class, new Block()); + return function(HttpResponseDecorator.class, this, "GetCookie", object.class, new Block((Body) () -> { + returnNormal(decoratedHttpResponse.ref().getCookie(pcName)); + })); } - @LegacySignature(type = Type.METHOD, name = "GetAdapter", qualified = "progress.lang.object", parameters = - { - @LegacyParameter(name = "poAdaptTo", type = "OBJECT", qualified = "progress.lang.class", mode = "INPUT") - }) - public object getAdapter(final object _poAdaptTo) + @LegacySignature(type = Type.METHOD, name = "GetAdapter", qualified = "progress.lang.object", parameters = { + @LegacyParameter(name = "poAdaptTo", type = "OBJECT", qualified = "progress.lang.class", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public object getAdapter( + final object _poAdaptTo) { object poAdaptTo = TypeFactory.initInput(_poAdaptTo); - - return function(HttpResponseDecorator.class, this, "GetAdapter", object.class, new Block()); + + return function(HttpResponseDecorator.class, this, "GetAdapter", object.class, + new Block((Body) () -> { + Assert.notNull(poAdaptTo, new character("Adapter")); + + if (getLegacyClass().ref()._isA(poAdaptTo)) + returnNormal(ObjectOps.thisObject()); + + if (ObjectOps.typeOf(decoratedHttpResponse, IAdaptable.class).booleanValue()) + returnNormal(ObjectOps.cast(decoratedHttpResponse, IAdaptable.class).ref().getAdapter(poAdaptTo)); + + returnNormal(new object()); + })); } } === modified file 'src/com/goldencode/p2j/oo/net/http/NullHeader.java' --- src/com/goldencode/p2j/oo/net/http/NullHeader.java 2020-09-04 09:39:33 +0000 +++ src/com/goldencode/p2j/oo/net/http/NullHeader.java 2021-01-11 07:55:39 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. +** 002 ME 20210111 Set name and value to null. */ /* @@ -105,6 +106,8 @@ internalProcedure(this, "__net_http_NullHeader_constructor__", new Block((Body) () -> { __net_http_HttpHeader_constructor__(); + name.setUnknown(); + value.setUnknown(); })); } === modified file 'src/com/goldencode/p2j/oo/net/http/ProxyHttpRequest.java' --- src/com/goldencode/p2j/oo/net/http/ProxyHttpRequest.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/ProxyHttpRequest.java 2020-11-05 09:13:00 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. ** 002 ME 20200410 Fully implement ISupportProxy interface. +** 20201105 Add missing constructor/execute. */ /* @@ -65,11 +66,15 @@ package com.goldencode.p2j.oo.net.http; import com.goldencode.p2j.util.*; +import com.goldencode.p2j.util.BlockManager.Action; +import com.goldencode.p2j.util.BlockManager.Condition; import com.goldencode.p2j.util.InternalEntry.Type; import static com.goldencode.p2j.report.ReportConstants.*; +import static com.goldencode.p2j.util.BlockManager.externalProcedure; import static com.goldencode.p2j.util.BlockManager.function; import static com.goldencode.p2j.util.BlockManager.internalProcedure; +import static com.goldencode.p2j.util.BlockManager.onBlockLevel; import static com.goldencode.p2j.util.BlockManager.returnNormal; import com.goldencode.p2j.oo.net.Uri; @@ -80,13 +85,21 @@ * */ @LegacyResource(resource = "OpenEdge.Net.HTTP.ProxyHttpRequest") -@LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL|RT_LVL_PARTIAL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class ProxyHttpRequest extends HttpRequestDecorator implements ISupportProxy { /** Proxy URI **/ private final object proxyUri = TypeFactory.object(Uri.class); + public void __net_http_ProxyHttpRequest_execute__() + { + externalProcedure(HttpRequestDecorator.class, ProxyHttpRequest.this, new Block((Body) () -> + { + onBlockLevel(Condition.ERROR, Action.THROW); + })); + } + /** * Get the URI used as proxy. * @@ -120,5 +133,18 @@ this.proxyUri.assign(proxyUri); })); } + + @LegacySignature(type = Type.CONSTRUCTOR, parameters = + { + @LegacyParameter(name = "poHttpRequest", type = "OBJECT", qualified = "openedge.net.http.ihttprequest", mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void __net_http_ProxyHttpRequest_constructor__(final object _poHttpRequest) + { + internalProcedure(HttpRequestDecorator.class, this, "__net_http_ProxyHttpRequest_constructor__", new Block((Body) () -> + { + __net_http_HttpRequestDecorator_constructor__(_poHttpRequest); + })); + } } === modified file 'src/com/goldencode/p2j/oo/net/http/RequestBuilder.java' --- src/com/goldencode/p2j/oo/net/http/RequestBuilder.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/RequestBuilder.java 2020-12-04 08:26:10 +0000 @@ -9,6 +9,8 @@ ** 002 CA 20191023 Fixed the LegacySignature.name for post method. ** 003 CA 20191024 Added method support levels and updated the class support level. ** 005 CA 20200503 Added stub for net.http.RequestBuilder:UsingBasicAuthentication. +** 006 ME 20201029 Fix typeof assert for builder type. +** 20201204 Minor fixes for validation and error messages. */ /* @@ -114,8 +116,20 @@ protected static final String TEXT_HTML = "text/html"; protected static final String FORM_URLENCODED = "application/x-www-form-urlencoded"; - protected static final String ACCEPT_CONTENT_TYPE = "AcceptContentType"; - + protected static final String OPTION_METHOD = "method"; + protected static final String OPTION_URI = "uri"; + protected static final String OPTION_ACCEPT_CONTENT_TYPE = "AcceptContentType"; + protected static final String OPTION_VERSION = "version"; + protected static final String OPTION_SUPPORT_AUTHENTICATION = "supportsAuthentication"; + protected static final String OPTION_SUPPORT_PROXY= "supportsProxy"; + protected static final String OPTION_PROXY_URI = "ProxyURI"; + protected static final String OPTION_ENTITY = "entity"; + protected static final String OPTION_EVENT_LISTENER_TYPE= "EventListenerType"; + protected static final String OPTION_AUTH_LISTENER= "Listener"; + protected static final String OPTION_AUTH_CREDENTIALS= "credentials"; + protected static final String OPTION_AUTH_METHOD= "authenticationMethod"; + protected static final String OPTION_AUTH_CHALLENGE= "challenge"; + protected static final String HANDLE = "HANDLE"; protected static final String CHAR = "CHARACTER"; protected static final String INPUT = "INPUT"; @@ -254,7 +268,7 @@ object builderType = getRegistry().ref() .get(builderCls.ref().getTypeName()); - Assert.isType(builderType, builderType); + Assert.isType(builderType, builderCls); object builder = ObjectOps .newInstance(builderType.ref().getType(), "II", pcMethod, poURI); @@ -635,7 +649,7 @@ { return function(RequestBuilder.class, "Options", object.class, new Block((Body) () -> { - returnNormal(build(MethodEnum.post.ref().toLegacyString(), _poURI).ref().withData(_poEntity, _pcContentType)); + returnNormal(build(MethodEnum.options.ref().toLegacyString(), _poURI).ref().withData(_poEntity, _pcContentType)); })); } @@ -965,8 +979,8 @@ Assert.notNullOrEmpty(pcMethod, new character("Method")); Assert.notNull(poURI, new character("URI")); - setOption(new character("uri"), poURI); - setOption(new character("method"), pcMethod); + setOption(new character(OPTION_URI), poURI); + setOption(new character(OPTION_METHOD), pcMethod); })); } @@ -1037,7 +1051,7 @@ * * @return The request builder being constructed. */ - @LegacySignature(type = Type.METHOD, name = ACCEPT_CONTENT_TYPE, + @LegacySignature(type = Type.METHOD, name = "AcceptContentType", qualified = REQUESTBUILDER, parameters = { @LegacyParameter(name = "pcContentType", type = CHAR, mode = INPUT) @@ -1047,15 +1061,12 @@ final character _pcContentType) { character pcContentType = TypeFactory.initInput(_pcContentType); - return function(this, ACCEPT_CONTENT_TYPE, object.class, new Block((Body)() -> + return function(this, "AcceptContentType", object.class, new Block((Body)() -> { - character ctype = new character(ACCEPT_CONTENT_TYPE); + character ctype = new character(OPTION_ACCEPT_CONTENT_TYPE); character cv = getOptionStringValue(ctype); - if (cv.isUnknown()) - { - cv.assign(new character("")); - }; - setOption(ctype, new character(cv + "," + pcContentType.getValue())); + + setOption(ctype, TextOps.substitute("&1,&2", cv.isUnknown() ? "" : cv, pcContentType)); returnNormal(new object(this)); })); } @@ -1151,10 +1162,7 @@ object handler = ObjectOps.newInstance(AuthFilterEventHandlerWrapper.class, "I", phListener); - returnNormal(addCallback(authClass, handler)); - - - returnNormal(new object(this)); + returnNormal(addCallback(poEventListenerType, handler)); })); } @@ -1189,8 +1197,8 @@ Assert.notNull(poListener, new character("Event listener")); supportsAuthentication(); - setOption(new character("EventListenerType"), poEventListenerType); - setOption(new character("Listener"), poListener); + setOption(new character(OPTION_EVENT_LISTENER_TYPE), poEventListenerType); + setOption(new character(OPTION_AUTH_LISTENER), poListener); returnNormal(new object(this)); })); @@ -1457,7 +1465,7 @@ { character pcETag = TypeFactory.initInput(_pcETag); return function(this, "ETag", object.class, new Block((Body) () -> { - Assert.notNullOrEmpty(pcETag, new character("ETag")); + Assert.notNullOrEmpty(pcETag, new character("ETag ")); returnNormal(addHeader(new character("ETag"), character.quoter(pcETag))); })); } @@ -1480,8 +1488,9 @@ character pcVersion = TypeFactory.initInput(_pcVersion); return function(this, "HttpVersion", object.class, new Block((Body) () -> { - Assert.notNullOrEmpty(pcVersion, new character("HTTP version")); - setOption(new character("version"), pcVersion); + Assert.legacyEquals(new character("HTTP/1.1"), pcVersion); + + setOption(new character(OPTION_VERSION), pcVersion); returnNormal(new object(this)); })); } @@ -1535,7 +1544,7 @@ public object supportsAuthentication() { return function(this, "SupportsAuthentication", object.class, new Block((Body) () -> { - setOption(new character("supportsAuthentication"), character.valueOf(true)); + setOption(new character(OPTION_SUPPORT_AUTHENTICATION), character.valueOf(true)); returnNormal(new object(this)); })); } @@ -1551,7 +1560,7 @@ public object supportsProxy() { return function(this, "SupportsProxy", object.class, new Block((Body) () -> { - setOption(new character("supportsProxy"), character.valueOf(true)); + setOption(new character(OPTION_SUPPORT_PROXY), character.valueOf(true)); returnNormal(new object(this)); })); } @@ -1599,7 +1608,7 @@ return function(this, "ViaProxy", object.class, new Block((Body) () -> { Assert.notNull(poProxyURI, new character("Proxy server URI")); supportsProxy(); - setOption(new character("ProxyURI"), poProxyURI); + setOption(new character(OPTION_PROXY_URI), poProxyURI); returnNormal(new object(this)); })); } @@ -1683,9 +1692,9 @@ return function(this, "WithData", object.class, new Block((Body) () -> { Assert.notNull(poEntity, new character("Data")); - Assert.notNullOrEmpty(pcContentType, new character("Content type'")); + Assert.notNullOrEmpty(pcContentType, new character("Content type")); - setOption(new character("entity"), poEntity); + setOption(new character(OPTION_ENTITY), poEntity); contentType(pcContentType); returnNormal(new object(this)); @@ -1740,7 +1749,7 @@ Assert.notNull(p1, new character("Credentials")); supportsAuthentication(); - setOption(new character("credentials"), p1); + setOption(new character(OPTION_AUTH_CREDENTIALS), p1); returnNormal(new object(this)); })); @@ -1764,8 +1773,8 @@ usingCredentials(p1); - setOption(new character("authenticationmethod"), p2); - setOption(new character("challenge"), p3); + setOption(new character(OPTION_AUTH_METHOD), p2); + setOption(new character(OPTION_AUTH_CHALLENGE), p3); returnNormal(new object(this)); })); === modified file 'src/com/goldencode/p2j/oo/net/http/ResponseBuilder.java' --- src/com/goldencode/p2j/oo/net/http/ResponseBuilder.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/ResponseBuilder.java 2020-11-03 13:19:22 +0000 @@ -6,7 +6,8 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. -** 002 MP 20200603 Add missing stubs taken by converting the skeleton using FWD. +** 002 MP 20200603 Add missing stubs taken by converting the skeleton using FWD. +** 003 ME 20201029 Implement as per OE12.2. */ /* @@ -73,6 +74,8 @@ import com.goldencode.p2j.oo.core.*; import com.goldencode.p2j.oo.core.util.ConfigBuilder; +import com.goldencode.p2j.oo.lang.LegacyClass; +import com.goldencode.p2j.oo.lang._BaseObject_; import com.goldencode.p2j.security.*; import com.goldencode.p2j.util.*; import com.goldencode.p2j.util.BlockManager.Action; @@ -84,7 +87,7 @@ * */ @LegacyResource(resource = "OpenEdge.Net.HTTP.ResponseBuilder") -@LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL|RT_LVL_PARTIAL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public abstract class ResponseBuilder extends ConfigBuilder implements ISupportInitialize @@ -101,11 +104,7 @@ @Override protected object initialValue() { - object registry = - UndoableFactory.object(BuilderRegistry.class); - registry.assign(ObjectOps.newInstance(BuilderRegistry.class)); - initializeRegistry(registry); - return registry; + return TypeFactory.object(BuilderRegistry.class); } }; @@ -133,7 +132,20 @@ { return function(null, "Registry", object.class, new Block((Body) () -> { - returnNormal(REGISTRY.get()); + object registry = REGISTRY.get(); + + if (!registry._isValid()) { + registry.assign(ObjectOps.newInstance(BuilderRegistry.class)); + + registry.ref()._put(ObjectOps.getLegacyName(IhttpResponse.class), + ObjectOps.getLegacyClass(HttpResponse.class)); + registry.ref()._put(ObjectOps.getLegacyName(ResponseBuilder.class), + ObjectOps.getLegacyClass(DefaultResponseBuilder.class)); + + REGISTRY.set(registry); + } + + returnNormal(registry); })); } @@ -141,15 +153,30 @@ public abstract object getResponse(); @LegacySignature(type = Type.METHOD, name = "Build", qualified = "openedge.net.http.responsebuilder") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static object build() { return function(ResponseBuilder.class, "Build", object.class, new Block((Body) () -> { - UnimplementedFeature.missing("ResponseBuilder:Build METHOD"); + object builderCls = ObjectOps + .getLegacyClass(ResponseBuilder.class); + object builderType = getRegistry().ref() + .get(builderCls.ref().getTypeName()); + + Assert.isType(builderType, builderCls); + + object builder = ObjectOps + .newInstance(builderType.ref().getType()); + + if (builder._isValid() && builder.ref() instanceof ISupportInitialize) + ((ISupportInitialize) builder.ref()).initialize(); + + returnNormal(builder); })); } @LegacySignature(type = Type.CONSTRUCTOR) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) protected void __net_http_ResponseBuilder_constructor__() { internalProcedure(ResponseBuilder.class, this, "__net_http_ResponseBuilder_constructor__", new Block((Body) () -> @@ -159,46 +186,31 @@ } @LegacySignature(type = Type.DESTRUCTOR) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_http_ResponseBuilder_destructor__() { internalProcedure(ResponseBuilder.class, this, "__net_http_ResponseBuilder_destructor__", new Block((Body) () -> { - UnimplementedFeature.missing("ResponseBuilder: DESTRUCTOR"); + destroy(); })); } - /** - * Initialize registry. - * - * @param _poRegistry registry to be initialized. - */ - @LegacySignature(type = Type.METHOD, name = "InitializeRegistry", parameters = - { - @LegacyParameter(name = "poRegistry", type = "OBJECT", - qualified = "openedge.net.http.builderregistry", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public static void initializeRegistry(final object _poRegistry) - { - internalProcedure(null, "InitializeRegistry", new Block((Body) ()-> { - _poRegistry.ref()._put(ObjectOps.getLegacyName(IhttpResponse.class), - ObjectOps.getLegacyClass( HttpResponse.class)); - _poRegistry.ref()._put(ObjectOps.getLegacyName(ResponseBuilder.class), - ObjectOps.getLegacyClass(DefaultResponseBuilder.class)); - })); - } - @LegacySignature(type = Type.METHOD, name = "HttpVersion", qualified = "openedge.net.http.responsebuilder", parameters = { @LegacyParameter(name = "pcVersion", type = "CHARACTER", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public object httpVersion(final character _pcVersion) { character pcVersion = TypeFactory.initInput(_pcVersion); return function(ResponseBuilder.class, this, "HttpVersion", object.class, new Block((Body) () -> { - UnimplementedFeature.missing("ResponseBuilder:HttpVersion METHOD"); + Assert.notNullOrEmpty(pcVersion, new character("HTTP version")); + + setOption(new character("version"), _pcVersion); + + returnNormal(new object(this)); })); } @@ -206,30 +218,28 @@ * Destroy. */ @LegacySignature(type = Type.METHOD, name = "Destroy") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public void destroy() { internalProcedure(ResponseBuilder.class, this, "Destroy", new Block((Body) () -> { - UnimplementedFeature.missing("ResponseBuilder:Destroy METHOD"); + // looks like no-op })); - // TODO Auto-generated method stub } /** * Initialize. */ @LegacySignature(type = Type.METHOD, name = "Initialize") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public void initialize() { internalProcedure(ResponseBuilder.class, this, "Initialize", new Block((Body) () -> { - UnimplementedFeature.missing("ResponseBuilder:Initialize METHOD"); + httpVersion(new character("HTTP/1.1")); })); - // TODO Auto-generated method stub } } === modified file 'src/com/goldencode/p2j/oo/net/http/StatefulHttpClient.java' --- src/com/goldencode/p2j/oo/net/http/StatefulHttpClient.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/StatefulHttpClient.java 2020-11-03 09:05:47 +0000 @@ -1,5 +1,5 @@ /* -** Module : SemicolonParamHeaderBuilder.java +** Module : StatefulHttpClient.java ** Abstract : Implementation of the builtin class. ** ** Copyright (c) 2019, Golden Code Development Corporation. @@ -8,6 +8,7 @@ ** 001 IAS 20190923 First version. ** 002 ME 20200410 Added getter/setter methods for cookie jar. ** 003 MP 20200603 add constructors and methods like originar class. +** 004 ME 20201103 Implement cookie support OE12.2. */ /* @@ -77,110 +78,157 @@ import static com.goldencode.p2j.util.BlockManager.onBlockLevel; import static com.goldencode.p2j.util.BlockManager.returnNormal; +import com.goldencode.p2j.oo.core.Assert; +import com.goldencode.p2j.oo.net.Uri; + /** * Http client with support for cookies * */ @LegacyResource(resource = "OpenEdge.Net.HTTP.StatefulHttpClient") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_PARTIAL) -public class StatefulHttpClient -extends HttpClientDecorator -implements ISupportCookies +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) +public class StatefulHttpClient extends HttpClientDecorator implements ISupportCookies { /** Cookie Jar **/ @LegacySignature(type = Type.PROPERTY, name = "CookieJar") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) private final object cookieJar = TypeFactory.object(ICookieJar.class); - - @LegacySignature(type = Type.METHOD, name = "Execute", parameters = - { - @LegacyParameter(name = "poRequest", type = "OBJECT", qualified = "openedge.net.http.ihttprequest", mode = "INPUT"), - @LegacyParameter(name = "poResponse", type = "OBJECT", qualified = "openedge.net.http.ihttpresponse", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + + @LegacySignature(type = Type.METHOD, name = "Execute", parameters = { + @LegacyParameter(name = "poRequest", type = "OBJECT", qualified = "openedge.net.http.ihttprequest", mode = "INPUT"), + @LegacyParameter(name = "poResponse", type = "OBJECT", qualified = "openedge.net.http.ihttpresponse", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) @Override public void execute( - final object _poRequest, + final object _poRequest, final object _poResponse) { - object poRequest = TypeFactory.initInput(_poRequest); - object poResponse = TypeFactory.initInput(_poResponse); - - internalProcedure(StatefulHttpClient.class, this, "Execute", new Block((Body) () -> - { - UnimplementedFeature.missing("StatefulHttpClient:Execute METHOD"); + object poRequest = TypeFactory + .initInput(_poRequest); + object poResponse = TypeFactory + .initInput(_poResponse); + + internalProcedure(StatefulHttpClient.class, this, "Execute", new Block((Body) () -> { + object oUri = poRequest.ref().getUri(); + object oCookies[][] = new object[][] { + TypeFactory.objectExtent(Cookie.class) }; + + // check if there are cookies in jar for request url + cookieJar.ref().getCookies(oUri, new OutputExtentParameter>() + { + + @Override + public object[] getVariable() + { + return oCookies[0]; + } + + @Override + public void setVariable(object[] reference) + { + oCookies[0] = reference; + } + }); + + // if there are any set those on request + if (oCookies[0].length > 0) + poRequest.ref().setCookies(oCookies[0]); + + oCookies[0] = ArrayAssigner.resize(oCookies[0], new integer()); + + getDecoratedHttpClient().ref().execute(poRequest, poResponse); + + // if we have cookies set in response save those in jar + poResponse.ref().getCookies(new OutputExtentParameter>() + { + + @Override + public object[] getVariable() + { + return oCookies[0]; + } + + @Override + public void setVariable(object[] reference) + { + oCookies[0] = reference; + } + }); + + if (oCookies[0].length > 0) { + + String host = oUri.ref().getHost().getValue().toLowerCase(); + + for (object cookie : oCookies[0]) + { + // RFC6265 - defaults and domain validation + character cpath = TextOps.isEmpty(cookie.ref().getPath()) ? oUri.ref().getPath() : cookie.ref().getPath(); + character cdomain = TextOps.isEmpty(cookie.ref().getDomain()) ? oUri.ref().getHost() : cookie.ref().getDomain(); + + String domain = cdomain.getValue().toLowerCase(); + if (domain.startsWith(".")) + domain = domain.substring(1); + + if (domain.equals(host) || host.endsWith("." + domain)) + cookieJar.ref().addCookie(cdomain, cpath, cookie); + } + } + })); } - + public void __net_http_StatefulHttpClient_execute__() { - externalProcedure(StatefulHttpClient.class, StatefulHttpClient.this, new Block((Init) () -> - { - ObjectOps.register(cookieJar); - }, - (Body) () -> - { - onBlockLevel(Condition.ERROR, Action.THROW); - { - } - })); + externalProcedure(StatefulHttpClient.class, StatefulHttpClient.this, + new Block((Body) () -> { + onBlockLevel(Condition.ERROR, Action.THROW); + })); } - - @LegacySignature(type = Type.CONSTRUCTOR, parameters = - { - @LegacyParameter(name = "poClient", type = "OBJECT", qualified = "openedge.net.http.ihttpclient", mode = "INPUT"), - @LegacyParameter(name = "poCookieJar", type = "OBJECT", qualified = "openedge.net.http.icookiejar", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + + @LegacySignature(type = Type.CONSTRUCTOR, parameters = { + @LegacyParameter(name = "poClient", type = "OBJECT", qualified = "openedge.net.http.ihttpclient", mode = "INPUT"), + @LegacyParameter(name = "poCookieJar", type = "OBJECT", qualified = "openedge.net.http.icookiejar", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void __net_http_StatefulHttpClient_constructor__( - final object _poClient, + final object _poClient, final object _poCookieJar) { - object poClient = TypeFactory.initInput(_poClient); - object poCookieJar = TypeFactory.initInput(_poCookieJar); - - internalProcedure(StatefulHttpClient.class, this, "__net_http_StatefulHttpClient_constructor__", new Block((Init) () -> - { - ObjectOps.register(poCookieJar, poClient); - }, - (Body) () -> - { - UnimplementedFeature.missing("StatefulHttpClient II CONSTRUCTOR"); - //__net_http_HttpClientDecorator_constructor__(); - })); - } - - @LegacySignature(type = Type.CONSTRUCTOR, parameters = - { - @LegacyParameter(name = "poClient", type = "OBJECT", qualified = "openedge.net.http.ihttpclient", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) - public void __net_http_StatefulHttpClient_constructor__(final object _poClient) - { - object poClient = TypeFactory.initInput(_poClient); - - internalProcedure(StatefulHttpClient.class, this, "__net_http_StatefulHttpClient_constructor__", new Block((Init) () -> - { - ObjectOps.register(poClient); - }, - (Body) () -> - { - __net_http_HttpClientDecorator_constructor__(poClient); - })); - } - + object poCookieJar = TypeFactory + .initInput(_poCookieJar); + + internalProcedure(StatefulHttpClient.class, this, + "__net_http_StatefulHttpClient_constructor__", new Block((Body) () -> { + __net_http_HttpClientDecorator_constructor__(_poClient); + + Assert.notNull(poCookieJar); + cookieJar.assign(poCookieJar); + })); + } + + @LegacySignature(type = Type.CONSTRUCTOR, parameters = { + @LegacyParameter(name = "poClient", type = "OBJECT", qualified = "openedge.net.http.ihttpclient", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void __net_http_StatefulHttpClient_constructor__( + final object _poClient) + { + internalProcedure(StatefulHttpClient.class, this, + "__net_http_StatefulHttpClient_constructor__", new Block((Body) () -> { + __net_http_HttpClientDecorator_constructor__(_poClient); + })); + } + /** * Get cookie storage. * * @return cookie jar. */ @LegacySignature(type = Type.GETTER, name = "CookieJar") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) @Override - public object getCookieJar(){ - return function(this, "CookieJar", object.class, new Block((Body) () -> - { + public object getCookieJar() + { + return function(this, "CookieJar", object.class, new Block((Body) () -> { returnNormal(cookieJar); })); } @@ -191,15 +239,16 @@ * @param _cookieJar The cookie jar. */ @LegacySignature(type = Type.SETTER, name = "CookieJar") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public void setCookieJar(object _cookieJar){ + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public void setCookieJar( + object _cookieJar) + { object cookieJar = TypeFactory.initInput(_cookieJar); - - internalProcedure(this, "CookieJar", new Block((Body) () -> - { + + internalProcedure(this, "CookieJar", new Block((Body) () -> { this.cookieJar.assign(cookieJar); })); } - + } === modified file 'src/com/goldencode/p2j/oo/net/http/StatusCodeHelper.java' --- src/com/goldencode/p2j/oo/net/http/StatusCodeHelper.java 2020-06-15 00:40:59 +0000 +++ src/com/goldencode/p2j/oo/net/http/StatusCodeHelper.java 2021-01-28 08:04:50 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 MP 20200603 First version, stubs taken by converting the skeleton using FWD. +** 002 MP 20201218 Implement as of OE12.2. ** */ @@ -67,11 +68,11 @@ import com.goldencode.p2j.util.*; import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; -import com.goldencode.p2j.util.InternalEntry.Type; +import com.goldencode.p2j.oo.core.Assert; import com.goldencode.p2j.oo.lang.*; import static com.goldencode.p2j.report.ReportConstants.CVT_LVL_FULL; -import static com.goldencode.p2j.report.ReportConstants.RT_LVL_STUB; +import static com.goldencode.p2j.report.ReportConstants.RT_LVL_FULL; import static com.goldencode.p2j.util.BlockManager.*; import static com.goldencode.p2j.util.InternalEntry.Type; @@ -80,13 +81,13 @@ * in OpenEdge/Net/HTTP/StatusCodeHelper.cls). */ @LegacyResource(resource = "OpenEdge.Net.HTTP.StatusCodeHelper") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class StatusCodeHelper extends BaseObject { public void __net_http_StatusCodeHelper_execute__() { - externalProcedure(StatusCodeHelper.class, StatusCodeHelper.this, new Block((Body) () -> + externalProcedure(StatusCodeHelper.this, new Block((Body) () -> { onBlockLevel(Condition.ERROR, Action.THROW); { @@ -95,7 +96,7 @@ } @LegacySignature(type = Type.CONSTRUCTOR) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_http_StatusCodeHelper_constructor__() { internalProcedure(StatusCodeHelper.class, this, "__net_http_StatusCodeHelper_constructor__", new Block((Body) () -> @@ -105,10 +106,10 @@ } @LegacySignature(type = Type.CONSTRUCTOR) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static void __net_http_StatusCodeHelper_constructor__static__() { - externalProcedure(HttpRequestError.class, new Block((Body) () -> + externalProcedure(StatusCodeHelper.class, new Block((Body) () -> { onBlockLevel(Condition.ERROR, Action.THROW); })); @@ -118,14 +119,198 @@ { @LegacyParameter(name = "piStatusCode", type = "INTEGER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static character getMessage(final integer _piStatusCode) { integer piStatusCode = TypeFactory.initInput(_piStatusCode); return function(StatusCodeHelper.class, "GetMessage", character.class, new Block((Body) () -> { - UnimplementedFeature.missing("StatusCodeHelper:GetMessage METHOD"); + + if (piStatusCode.isUnknown() || piStatusCode.intValue() < 0) + { + returnNormal(StatusCodeEnum.unknown.ref().toLegacyString()); + } + + switch(piStatusCode.intValue()) + { + case(0): + returnNormal(StatusCodeEnum.none.ref().toLegacyString()); + break; + case(101): + returnNormal(new character("Switching Protocols")); + break; + case(102): + returnNormal(new character("Processing")); + break; + case(200): + returnNormal(new character("OK")); + break; + case(201): + returnNormal(new character("Created")); + break; + case(202): + returnNormal(new character("Accepted")); + break; + case(203): + returnNormal(new character("Non Authoritative Information")); + break; + case(204): + returnNormal(new character("No Content")); + break; + case(205): + returnNormal(new character("Reset Content")); + break; + case(206): + returnNormal(new character("Partial Content")); + break; + case(207): + returnNormal(new character("Multi-Status")); + break; + case(208): + returnNormal(new character("Already Reported")); + break; + case(226): + returnNormal(new character("IM Used")); + break; + case(300): + returnNormal(new character("Multiple Choices")); + break; + case(301): + returnNormal(new character("Moved Permanently")); + break; + case(302): + returnNormal(new character("Found")); + break; + case(303): + returnNormal(new character("See Other")); + break; + case(304): + returnNormal(new character("Not Modified")); + break; + case(305): + returnNormal(new character("Use Proxy")); + break; + case(307): + returnNormal(new character("Temporary Redirect")); + break; + case(308): + returnNormal(new character("Permanent Redirect")); + break; + case(400): + returnNormal(new character("Bad Request")); + break; + case(401): + returnNormal(new character("Unauthorized")); + break; + case(402): + returnNormal(new character("Payment Required")); + break; + case(403): + returnNormal(new character("Forbidden")); + break; + case(404): + returnNormal(new character("Not Found")); + break; + case(405): + returnNormal(new character("Method Not Allowed")); + break; + case(406): + returnNormal(new character("Not Acceptable")); + break; + case(407): + returnNormal(new character("Proxy Authentication Required")); + break; + case(408): + returnNormal(new character("Request Timeout")); + break; + case(409): + returnNormal(new character("Conflict")); + break; + case(410): + returnNormal(new character("Gone")); + break; + case(411): + returnNormal(new character("Length Required")); + break; + case(412): + returnNormal(new character("Precondition Failed")); + break; + case(413): + returnNormal(new character("Request Entity Too Large")); + break; + case(414): + returnNormal(new character("Request URI Too Large")); + break; + case(415): + returnNormal(new character("Unsupported Media Type")); + break; + case(416): + returnNormal(new character("Requested Range Not Satisfiable")); + break; + case(417): + returnNormal(new character("Expectation Failed")); + break; + case(421): + returnNormal(new character("Misdirected Request")); + break; + case(422): + returnNormal(new character("Unprocessable Entity")); + break; + case(423): + returnNormal(new character("Locked")); + break; + case(424): + returnNormal(new character("Failed Dependency")); + break; + case(426): + returnNormal(new character("Upgrade Required")); + break; + case(428): + returnNormal(new character("Precondition Required")); + break; + case(429): + returnNormal(new character("Too Many Requests")); + break; + case(431): + returnNormal(new character("Request Header Fields Too Large")); + break; + case(500): + returnNormal(new character("Internal Server Error")); + break; + case(501): + returnNormal(new character("Not Implemented")); + break; + case(502): + returnNormal(new character("Bad Gateway")); + break; + case(503): + returnNormal(new character("Service Unavailable")); + break; + case(504): + returnNormal(new character("Gateway Timeout")); + break; + case(505): + returnNormal(new character("HTTP Version Not Supported")); + break; + case(506): + returnNormal(new character("Variant Also Negotiates")); + break; + case(507): + returnNormal(new character("Insufficient Storage")); + break; + case(508): + returnNormal(new character("Loop Detected")); + break; + case(510): + returnNormal(new character("Not Extended")); + break; + case(511): + returnNormal(new character("Network AuthenticationRequired")); + break; + default: + returnNormal(StatusCodeEnum.unknown.ref().toLegacyString()); + } })); } @@ -133,14 +318,20 @@ { @LegacyParameter(name = "poStatusCode", type = "OBJECT", qualified = "openedge.net.http.statuscodeenum", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static character getMessage(final object _poStatusCode) { object poStatusCode = TypeFactory.initInput(_poStatusCode); return function(StatusCodeHelper.class, "GetMessage", character.class, new Block((Body) () -> { - UnimplementedFeature.missing("StatusCodeHelper:GetMessage METHOD"); + if (!poStatusCode._isValid()) + { + returnNormal(StatusCodeEnum.unknown.ref().toLegacyString()); + } + + returnNormal(getMessage(new integer(poStatusCode.ref().getValue()))); + })); } @@ -148,14 +339,29 @@ { @LegacyParameter(name = "pcStatusMessage", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static object getCode(final character _pcStatusMessage) { character pcStatusMessage = TypeFactory.initInput(_pcStatusMessage); return function(StatusCodeHelper.class, "GetCode", object.class, new Block((Body) () -> { - UnimplementedFeature.missing("StatusCodeHelper:GetCode METHOD"); + Assert.notNull(pcStatusMessage, new character("Status message")); + + if (TextOps.isEmpty(pcStatusMessage)) + { + returnNormal(StatusCodeEnum.none); + } + + character enumValues = TypeFactory.initInput(StatusCodeEnum.getEnumNames(StatusCodeEnum.class)); + + if (TextOps.lookup(TextOps.toLowerCase(pcStatusMessage), TextOps.toLowerCase(enumValues)).intValue() == 0) + { + returnNormal(StatusCodeEnum.unknown); + } + + returnNormal(StatusCodeEnum.getEnum(pcStatusMessage)); + })); } } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/auth/AuthFilterEventHandlerWrapper.java' --- src/com/goldencode/p2j/oo/net/http/filter/auth/AuthFilterEventHandlerWrapper.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/auth/AuthFilterEventHandlerWrapper.java 2020-12-04 08:14:49 +0000 @@ -6,6 +6,8 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 ME 20200508 First version. +** 20201127 Fix error messages to avoid truncation of character (default format X8). +** 20201204 Use compare for lookup value to account for unknown internal entries (proxy procedures). */ /* @@ -128,21 +130,21 @@ if (!phCallbackProcedure.isType(LegacyResource.PROCEDURE)) returnError(ObjectOps.newInstance(AssertionFailedError.class, "II", "Callback is not a procedure handle (is of type )" - + phCallbackProcedure.getTypeName(), + + phCallbackProcedure.unwrapType().getResourceType().getValue(), 0)); PersistentProcedure hProc = phCallbackProcedure.unwrapProcedure(); - if (TextOps.lookup(eventHandlerName, hProc.internalEntries()).intValue() == 0) + if (CompareOps._isEqual(TextOps.lookup(eventHandlerName, hProc.internalEntries()), 0)) returnError(AppError.newInstance(String.format( "Unable to find event handle procedure \"%s\" in callback procedure %s", - eventHandlerName, hProc.getFileName()), 0)); + eventHandlerName, hProc.getFileName().getValue()), 0)); if (!eventHandlerSig .equalsIgnoreCase(hProc.getSignature(eventHandlerName).getValue())) returnError(AppError.newInstance(String.format( - "The signature of \"%s\" in %s does not match the interface definition in ", - eventHandlerName, hProc.getFileName(), eventHandlerInterface), 0)); + "The signature of %s in %s does not match the interface definition in %s", + eventHandlerName, hProc.getFileName().getValue(), eventHandlerInterface), 0)); callback.assign(phCallbackProcedure); })); === modified file 'src/com/goldencode/p2j/oo/net/http/filter/auth/AuthenticationRequestFilter.java' --- src/com/goldencode/p2j/oo/net/http/filter/auth/AuthenticationRequestFilter.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/auth/AuthenticationRequestFilter.java 2020-11-09 09:54:21 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. ** 002 ME 20200508 Implementation as of OE 11.7.4. +** 20201109 Throw 3135 error if listeners list not valid (initialize). */ /* @@ -104,8 +105,6 @@ @LegacySignature(type = Type.PROPERTY, name = "Message") private object message = TypeFactory.object(IhttpRequest.class); - //Warning - in 4gl message property is IHttpMessage. - //Because is used as IHttpRequest and to avoid several cast operations, type is changed @LegacySignature(type = Type.PROPERTY, name = "AuthenticatedRequest") private object authenticatedRequest = TypeFactory @@ -342,6 +341,11 @@ { internalProcedure(AuthenticationRequestFilter.class, this, "Destroy", new Block((Body) () -> { + if (moListeners == null) + { + ErrorManager.recordOrThrowError(3135, "Invalid handle. Not initialized or points to a deleted object"); + } + while (!moListeners.empty()) { unsubscribeListener(moListeners.pop()); === modified file 'src/com/goldencode/p2j/oo/net/http/filter/auth/BasicAuthenticationFilter.java' --- src/com/goldencode/p2j/oo/net/http/filter/auth/BasicAuthenticationFilter.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/auth/BasicAuthenticationFilter.java 2020-11-09 13:19:28 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. ** 002 ME 20200508 Implementation as of OE 11.7.4. +** 20201109 Replace string format with substitute. */ /* @@ -77,8 +78,6 @@ import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.*; -import java.util.Base64; - /** * * Sets the credentials for the Basic challenge. These will be @@ -135,7 +134,7 @@ if (!credentials._isValid()) undoThrow(AppError.newInstance( - String.format("Missing credentials for realm \"%s\"", realm), 0)); + TextOps.substitute("Missing credentials for realm \"&1\"", realm), new integer(0))); character cCredentials = TypeFactory.character(); @@ -147,7 +146,7 @@ getMessage().ref() .setHeader(HttpHeaderBuilder.build(new character("Authorization")) .ref() - .value(new character(String.format("Basic %s", authHeader.getValue()))) + .value(TextOps.substitute("Basic &1", authHeader)) .ref().getHeader()); })); } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/auth/DigestAuthenticationFilter.java' --- src/com/goldencode/p2j/oo/net/http/filter/auth/DigestAuthenticationFilter.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/auth/DigestAuthenticationFilter.java 2020-11-11 08:05:06 +0000 @@ -7,6 +7,8 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 CA 20190924 First version. ** 002 CA 20191024 Added method support levels and updated the class support level. +** 003 ME 20201111 Remove dependency on StringUtils, cosmetics. +* */ /* @@ -74,8 +76,7 @@ import com.goldencode.p2j.util.BlockManager.Condition; import com.goldencode.p2j.util.InternalEntry.Type; -import org.apache.commons.lang.StringUtils; -import java.util.LinkedList; +import java.util.HashMap; import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.*; @@ -88,11 +89,11 @@ * */ @LegacyResource(resource = "OpenEdge.Net.HTTP.Filter.Auth.DigestAuthenticationFilter") -@LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL | RT_LVL_FULL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public class DigestAuthenticationFilter extends AuthenticationRequestFilter { /* List of nounces */ - protected LinkedList nonceList = new LinkedList<>(); + protected HashMap nonceList = new HashMap(); public void __net_http_filter_auth_DigestAuthenticationFilter_execute__() { @@ -105,7 +106,7 @@ @LegacySignature(type = Type.CONSTRUCTOR, parameters = { @LegacyParameter(name = "poRequest", type = "OBJECT", qualified = "openedge.net.http.iauthenticatedrequest", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL | RT_LVL_FULL) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void __net_http_filter_auth_DigestAuthenticationFilter_constructor__( final object _poRequest) { @@ -120,7 +121,7 @@ } @LegacySignature(type = Type.DESTRUCTOR) - @LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL | RT_LVL_FULL) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void __net_http_filter_auth_DigestAuthenticationFilter_destructor__() { internalProcedure(DigestAuthenticationFilter.class, this, @@ -134,7 +135,7 @@ * Build the actual authentication. */ @LegacySignature(type = Type.METHOD, name = "AddAuthentication") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) @Override protected void addAuthetication() { @@ -154,7 +155,6 @@ raw rResponse = TypeFactory.raw(); character cCredentials = TypeFactory.character(); character cClientNonce = TypeFactory.character(); - integer nonceCount = TypeFactory.integer(); object oCredentials = TypeFactory.object(Credentials.class); object oRequest = TypeFactory.object(IhttpRequest.class); @@ -165,55 +165,46 @@ cOpaque.setUnknown(); lStale.setUnknown(); - String jSChallenge = ""; oRequest.assign(this.getMessage()); character cChallengeInit = this.getAuthenticatedRequest().ref().getAuthenticationChallenge(); - if (cChallengeInit.isUnknown()) - cRealm.setUnknown(); - else + if (!cChallengeInit.isUnknown()) { int jPos = cChallengeInit.getValue().indexOf(" "); - jSChallenge = cChallengeInit.getValue().substring(jPos + 1); - } - - String[] jSAChallenge = jSChallenge.split(","); - - for(String elem : jSAChallenge) - { - String entryKey = elem.split("=")[0].trim(); - String paramValue = ""; - int equalPos = elem.indexOf("="); - if (equalPos != -1) + String jSChallenge = cChallengeInit.getValue().substring(jPos + 1); + + for(String elem : jSChallenge.split(",")) { - paramValue = elem.substring(equalPos + 1).trim(); - StringUtils.removeStart(paramValue, "\""); - StringUtils.removeEnd(paramValue, "\""); + String[] entries = TextOps.entries(elem, "="); + + String entryKey = entries[0].trim().toLowerCase(); + character paramValue = entries.length == 1 ? TypeFactory.character() : TextOps.trim(entries[1], " \""); + + switch (entryKey) { + case "realm": + cRealm.assign(paramValue); + break; + case "domain": + cDomain.assign(paramValue); + break; + case "nonce": + cNonce.assign(paramValue); + break; + case "opaque": + cOpaque.assign(paramValue); + break; + case "stale": + lStale.assign(paramValue); + break; + case "algorithm": + cAlgorithm.assign(paramValue); + break; + case "qop": + cQualityOfProtection.assign(paramValue); + lServerSentQoP.assign(new logical(true)); + break; + } } - switch (entryKey) { - case "realm": - cRealm.assign(new character(paramValue)); - break; - case "domain": - cDomain.assign(new character(paramValue)); - break; - case "nonce": - cNonce.assign(new character(paramValue)); - break; - case "opaque": - cOpaque.assign(new character(paramValue)); - break; - case "stale": - lStale.assign(new logical(paramValue)); - break; - case "algorithm": - cAlgorithm.assign(new character(paramValue)); - break; - case "qop": - cQualityOfProtection.assign(new character(paramValue)); - lServerSentQoP.assign(new logical(true)); - break; - } } Assert.notNull(cRealm, new character("Realm")); @@ -224,9 +215,8 @@ cClientNonce = SecurityOps.hexEncode(SecurityOps.generateUUID()); - nonceCount = new integer(NextNonceCount(cNonce.getValue())); - String intToHex8Pad = Integer.toHexString(nonceCount.intValue()); - intToHex8Pad = StringUtils.leftPad(intToHex8Pad, 8, "0"); + String intToHex8Pad = Integer.toHexString(NextNonceCount(cNonce)); + character cToHex8Pad = TextOps.substitute("&1&2", character.fill("0", 8 - intToHex8Pad.length()), intToHex8Pad); switch(cAlgorithm.getValue()) { @@ -272,7 +262,7 @@ rResponse.assign(SecurityOps.md5Digest(TextOps.substitute("&1:&2:&3:&4:&5:&6", SecurityOps.hexEncode(rHash1), cNonce, - new character(intToHex8Pad), + cToHex8Pad, cClientNonce, cQualityOfProtection, SecurityOps.hexEncode(rHash2)) @@ -287,7 +277,7 @@ rResponse.assign(SecurityOps.md5Digest(TextOps.substitute("&1:&2:&3:&4:&5:&6", SecurityOps.hexEncode(rHash1), cNonce, - new character(intToHex8Pad), + cToHex8Pad, cClientNonce, cQualityOfProtection, SecurityOps.hexEncode(rHash2)) @@ -320,7 +310,7 @@ cCredentials.assign(TextOps.substitute("&1,cnonce=\"&2\",nc=&3,qop=\"&4\"", cCredentials, cClientNonce, - new character(intToHex8Pad), + cToHex8Pad, cQualityOfProtection)); } @@ -330,40 +320,21 @@ })); } - private int NextNonceCount(String pNonce) - { - int response = 0; - if (!nonceList.isEmpty()) - { - for (int i = 0; i < nonceList.size(); i++) - { - NonceEntity nc = nonceList.get(i); - if(nc.nonce.equals(pNonce)) - { - nc.count = nc.count + 1; - response = nc.count; - } - } - } - if(response == 0) - { - NonceEntity newEnt = new NonceEntity(pNonce); - nonceList.push(newEnt); - newEnt.count = newEnt.count + 1; - response = newEnt.count; - } - return response; - } - - private static class NonceEntity - { - public String nonce; - public int count; + private int NextNonceCount(character pNonce) + { + + integer count = nonceList.get(pNonce); + + if (count != null) + { + count.assign(count.intValue() + 1); + } + else + { + count = TypeFactory.integer(1L); + nonceList.put(pNonce, count); + } - NonceEntity(String nonce) - { - this.nonce = nonce; - this.count = 0; - } - } + return count.intValue(); + } } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/auth/NoAuthenticationFilter.java' --- src/com/goldencode/p2j/oo/net/http/filter/auth/NoAuthenticationFilter.java 2020-05-08 15:12:53 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/auth/NoAuthenticationFilter.java 2020-11-11 08:50:01 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. ** 002 ME 20200508 Implementation as of OE 11.7.4. +** 20201109 Update support levels. */ /* @@ -79,7 +80,7 @@ * */ @LegacyResource(resource = "OpenEdge.Net.HTTP.Filter.Auth.NoAuthenticationFilter") -@LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL | RT_LVL_FULL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public class NoAuthenticationFilter extends AuthenticationRequestFilter { public void __net_http_filter_auth_NoAuthenticationFilter_execute__() @@ -92,12 +93,10 @@ @LegacySignature(type = Type.CONSTRUCTOR, parameters = { @LegacyParameter(name = "poRequest", type = "OBJECT", qualified = "openedge.net.http.iauthenticatedrequest", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL | RT_LVL_FULL) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void __net_http_filter_auth_NoAuthenticationFilter_constructor__( - final object _poRequest) + final object poRequest) { - object poRequest = TypeFactory.initInput(_poRequest); - internalProcedure(NoAuthenticationFilter.class, this, "__net_http_filter_auth_NoAuthenticationFilter_constructor__", new Block((Body) () -> === modified file 'src/com/goldencode/p2j/oo/net/http/filter/payload/BinaryBodyWriter.java' --- src/com/goldencode/p2j/oo/net/http/filter/payload/BinaryBodyWriter.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/payload/BinaryBodyWriter.java 2020-12-07 13:16:33 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. ** 002 MP 20200707 Add code in methods to get similar behavior like legacy class +** 003 ME 20201207 Refactor write method taking object as input, fix assert error. */ /* @@ -249,30 +250,13 @@ returnNormal(new int64(0)); } - if (ObjectOps.typeOf(poData, Memptr.class).booleanValue()) - { - memptr nPtr = TypeFactory.memptr(); - object omemptr = ObjectOps.cast(poData, Memptr.class); - - try - { - nPtr.assign(omemptr.ref().getValue()); - returnNormal(write(nPtr)); - } - finally - { - if (nPtr.lengthOf() > 0) - nPtr.setLength(0); - } - } - else if (ObjectOps.typeOf(poData, ImemptrHolder.class).booleanValue()) - { - memptr nPtr = TypeFactory.memptr(); - object omemptr = ObjectOps.cast(poData, ImemptrHolder.class); - - try - { - nPtr.assign(omemptr.ref().getValue()); + if (ObjectOps.typeOf(poData, Memptr.class).booleanValue() || ObjectOps.typeOf(poData, ImemptrHolder.class).booleanValue()) + { + memptr nPtr = TypeFactory.memptr(); + + try + { + nPtr.assign(ObjectOps.typeOf(poData, Memptr.class).booleanValue() ? ObjectOps.cast(poData, Memptr.class).ref().getValue() : ObjectOps.cast(poData, ImemptrHolder.class).ref().getValue()); returnNormal(write(nPtr)); } finally @@ -286,17 +270,22 @@ object obucket = ObjectOps.cast(poData, ByteBucket.class); bucket().putBytes(obucket); } - else if (ObjectOps.typeOf(poData, LegacyString.class).booleanValue()) - { - returnNormal(write(ObjectOps.cast(poData, LegacyString.class).ref().getValue())); - } - else if (ObjectOps.typeOf(poData, IlongcharHolder.class).booleanValue()) - { - returnNormal(write(ObjectOps.cast(poData, IlongcharHolder.class).ref().getValue())); - } - else if (ObjectOps.typeOf(poData, IcharacterHolder.class).booleanValue()) - { - returnNormal(write(new longchar(ObjectOps.cast(poData, IcharacterHolder.class).ref().getValue()))); + else if (ObjectOps.typeOf(poData, LegacyString.class).booleanValue() || + ObjectOps.typeOf(poData, IlongcharHolder.class).booleanValue() || + ObjectOps.typeOf(poData, IcharacterHolder.class).booleanValue()) + { + longchar lChar = TypeFactory.longchar(); + + if (ObjectOps.typeOf(poData, LegacyString.class).booleanValue()) + lChar.assign( ObjectOps.cast(poData, LegacyString.class).ref().getValue()); + else if (ObjectOps.typeOf(poData, IlongcharHolder.class).booleanValue()) + lChar.assign( ObjectOps.cast(poData, IlongcharHolder.class).ref().getValue()); + else + lChar.assign( ObjectOps.cast(poData, IcharacterHolder.class).ref().getValue()); + + bucket().putString(lChar); + + returnNormal(TextOps.byteLength(lChar)); } else if (ObjectOps.typeOf(poData, FileInputStream.class).booleanValue()) { === modified file 'src/com/goldencode/p2j/oo/net/http/filter/payload/BinaryEntityWriter.java' --- src/com/goldencode/p2j/oo/net/http/filter/payload/BinaryEntityWriter.java 2020-06-15 00:40:59 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/payload/BinaryEntityWriter.java 2021-01-11 09:49:06 +0000 @@ -6,6 +6,8 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. +** 002 MP 20210106 Test as of OE12.2. +** ME 20210111 Use notNull method on Assert (null mixed with unknown for various data types). */ /* @@ -84,7 +86,7 @@ * */ @LegacyResource(resource = "OpenEdge.Net.HTTP.Filter.Payload.BinaryEntityWriter") -@LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL|RT_LVL_PARTIAL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class BinaryEntityWriter extends MessageWriter implements ISupportTransferEncoding @@ -193,6 +195,7 @@ { return function(this, "Write", int64.class, new Block((Body) () -> { + Assert.notNull(_pData, new character("Data")); writeInternal(_pData); })); } @@ -214,6 +217,8 @@ { return function(this, "Write", int64.class, new Block((Body) () -> { + Assert.notNull(_pData, new character("Data")); + writeInternal(_pData); })); } @@ -300,7 +305,6 @@ memptr ptr = TypeFactory.memptr(); try { - Assert.notNullBase(pData, new character("Data")); ptr.setLength(TextOps.length(pData).longValue() + 1); ptr.setString(pData, 1); returnNormal(write(ptr)); === modified file 'src/com/goldencode/p2j/oo/net/http/filter/payload/ConnectRequestFilter.java' --- src/com/goldencode/p2j/oo/net/http/filter/payload/ConnectRequestFilter.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/payload/ConnectRequestFilter.java 2021-01-28 08:38:48 +0000 @@ -6,7 +6,9 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 MP 20200603 First version, stubs taken by converting the skeleton using FWD. -** 001 MP 20200707 Add code in constructor and method +** 002 MP 20200707 Add code in constructor and methods +** 003 MP 20210106 Improve code based on existing tests - as OE12.2 +* */ /* @@ -76,7 +78,6 @@ import com.goldencode.p2j.oo.core.Assert; import com.goldencode.p2j.oo.core.ByteBucket; import com.goldencode.p2j.oo.lang.AppError; -import com.goldencode.p2j.oo.net.UriSchemeEnum; import com.goldencode.p2j.oo.net.http.IhttpRequest; /** @@ -88,6 +89,7 @@ public class ConnectRequestFilter extends com.goldencode.p2j.oo.net.http.filter.payload.MessageWriter { + public void __net_http_filter_payload_ConnectRequestFilter_execute__() { externalProcedure(ConnectRequestFilter.class, ConnectRequestFilter.this, new Block((Body) () -> @@ -122,7 +124,7 @@ { Assert.isType(pData, ObjectOps.getLegacyClass(IhttpRequest.class)); - int64 prevSize = ObjectOps.cast(this.entity, ByteBucket.class).ref().getSize(); + int64 prevSize = bucket().getSize(); object req = ObjectOps.cast(pData, IhttpRequest.class); Assert.notNull(req.ref().getUri(), new character("Request URI")); @@ -132,11 +134,13 @@ Assert.notNullOrEmpty(host, new character("Host name")); if(port.isUnknown()) { - if(req.ref().getUri().ref().getScheme().toString() == UriSchemeEnum.http.toString()) + String scheme = req.ref().getUri().ref().getScheme().getValue(); + + if( scheme.equals("http")) { port.assign(80); } - if(req.ref().getUri().ref().getScheme().toString() == UriSchemeEnum.https.toString()) + if( scheme.equals("https")) { port.assign(443); } @@ -147,26 +151,26 @@ undoThrowTopLevel(AppError.newInstance(TextOps.substitute("Port is too large: &1 (max allowed: 65535)", port.intValue()).getValue(), 0)); } character reqUri = new character(TextOps.substitute("&1:&2", host.getValue(), port.intValue())); - - // CONNECT - ObjectOps.cast(this.entity, ByteBucket.class).ref() - .putString(new longchar(TextOps.substitute("CONNECT &1 &2&3", reqUri, req.ref().getVersion(), new character("~r~n")))); - - // HEADERS - ObjectOps.cast(this.entity, ByteBucket.class).ref() - .putString(new longchar(TextOps.substitute("Host: &1&2", reqUri, new character("~r~n")))); - ObjectOps.cast(this.entity, ByteBucket.class).ref() - .putString(new longchar(TextOps.substitute("&1&2", - req.ref().getHeader(new character("User-Agent")).ref().toLegacyString(), - new character("~r~n")))); - ObjectOps.cast(this.entity, ByteBucket.class).ref() - .putString(new longchar(TextOps.substitute("Connection: keep-alive&1", new character("~r~n")))); - - /* ALWAYS add a trailing CRLF to indicate end of headers. */ - ObjectOps.cast(this.entity, ByteBucket.class).ref() - .putString(new longchar(new character("~r~n"))); - - returnNormal(MathOps.minus(ObjectOps.cast(this.entity, ByteBucket.class).ref().getSize(), prevSize)); + longchar CRLF = TypeFactory.longchar("~r~n"); + + //add connect line + bucket().putString(new longchar(TextOps.substitute("CONNECT &1 &2", reqUri, req.ref().getVersion()))); + bucket().putString(CRLF); + + //add headers + bucket().putString(new longchar(TextOps.substitute("Host: &1", reqUri))); + bucket().putString(CRLF); + + bucket().putString(new longchar(req.ref().getHeader(new character("User-Agent")).ref().toLegacyString())); + bucket().putString(CRLF); + + bucket().putString(new longchar("Connection: keep-alive")); + bucket().putString(CRLF); + + //add final CRLF who indicate end of headers + bucket().putString(CRLF); + + returnNormal(MathOps.minus(bucket().getSize(), prevSize)); })); } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/payload/DefaultRequestFilter.java' --- src/com/goldencode/p2j/oo/net/http/filter/payload/DefaultRequestFilter.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/payload/DefaultRequestFilter.java 2021-01-28 08:38:48 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 MP 20200603 First version, stubs taken by converting the skeleton using FWD. +** 002 MP 20210108 Adapt error message and do a cast for method access ** */ @@ -76,14 +77,11 @@ import java.util.concurrent.atomic.AtomicReference; -import org.apache.commons.lang3.StringUtils; - import com.goldencode.p2j.oo.core.ByteBucket; import com.goldencode.p2j.oo.core.HashAlgorithmEnum; import com.goldencode.p2j.oo.core.IAdaptable; import com.goldencode.p2j.oo.core.assertion.AssertObject; import com.goldencode.p2j.oo.lang.AppError; -import com.goldencode.p2j.oo.lang.LegacyClass; import com.goldencode.p2j.oo.lang._BaseObject_; import static com.goldencode.p2j.util.character.*; @@ -93,7 +91,6 @@ import com.goldencode.p2j.oo.net.http.HttpHeader; import com.goldencode.p2j.oo.net.http.ISupportProxy; import com.goldencode.p2j.oo.net.http.IhttpRequest; -import com.goldencode.p2j.oo.net.http.ProxyHttpClient; import com.goldencode.p2j.oo.net.http.TransferEncodingEnum; import com.goldencode.p2j.oo.net.http.filter.writer.BodyWriterBuilder; import com.goldencode.p2j.oo.net.http.filter.writer.MessageWriterBuilder; @@ -133,19 +130,19 @@ }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) @Override - public int64 write(final object _poData) + public int64 write(final object _poData) { - object poData = TypeFactory.initInput(_poData); + object poData = TypeFactory.initInput(_poData); return function(DefaultRequestFilter.class, this, "Write", int64.class, new Block((Body) () -> { AssertObject.isType(poData, ObjectOps.getLegacyClass(IhttpRequest.class)); - int64 prevSize = ObjectOps.cast(this.getEntity(), ByteBucket.class).ref().getSize(); + int64 prevSize = bucket().getSize(); this.writeMessage(ObjectOps.cast(poData, IhttpRequest.class)); - int64 actualSize = ObjectOps.cast(this.getEntity(), ByteBucket.class).ref().getSize(); + int64 actualSize = bucket().getSize(); returnNormal(actualSize.intValue() - prevSize.intValue()); @@ -157,9 +154,9 @@ @LegacyParameter(name = "poRequest", type = "OBJECT", qualified = "openedge.net.http.ihttprequest", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - protected void writeMessage(final object _poRequest) + protected void writeMessage(final object _poRequest) { - object poRequest = TypeFactory.initInput(_poRequest); + object poRequest = TypeFactory.initInput(_poRequest); internalProcedure(DefaultRequestFilter.class, this, "WriteMessage", new Block((Body) () -> { @@ -178,11 +175,11 @@ this.writeRequestLine(poRequest); this.writeHeaders(poRequest); - ObjectOps.cast(this.getEntity(), ByteBucket.class).ref().putString(new longchar(TextOps.concat(chr(13), chr(10)))); + bucket().putString(new longchar(TextOps.concat(chr(13), chr(10)))); if (poRequest.ref().getContentLength().intValue() >= 0) { - ObjectOps.cast(this.getEntity(), ByteBucket.class).ref().putBytes(oByteBucket); + bucket().putBytes(oByteBucket); } })); @@ -193,9 +190,9 @@ @LegacyParameter(name = "poRequest", type = "OBJECT", qualified = "openedge.net.http.ihttprequest", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - protected object extractEntity(final object _poRequest) + protected object extractEntity(final object _poRequest) { - //object poRequest = TypeFactory.initInput(_poRequest); + object poRequest = TypeFactory.initInput(_poRequest); return function(DefaultRequestFilter.class, this, "ExtractEntity", object.class, new Block((Body) () -> { @@ -215,7 +212,9 @@ if (!oBodyWriter._isValid()) { - undoThrowTopLevel(AppError.newInstance("Unable to build request for transmission", 0)); + String errMsg = "Unable to build request for transmission: no builder available for Content-Type: "; + errMsg = errMsg + poRequest.ref().getContentType().getValue(); + undoThrowTopLevel(AppError.newInstance(errMsg, 0)); } oBodyWriter.ref().open(); @@ -251,9 +250,9 @@ @LegacyParameter(name = "poRequest", type = "OBJECT", qualified = "openedge.net.http.ihttprequest", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - protected void writeRequestLine(final object _poRequest) + protected void writeRequestLine(final object _poRequest) { - object poRequest = TypeFactory.initInput(_poRequest); + object poRequest = TypeFactory.initInput(_poRequest); internalProcedure(DefaultRequestFilter.class, this, "WriteRequestLine", new Block((Body) () -> { @@ -273,7 +272,7 @@ if (oSuppProxy._isValid() && oSuppProxy.ref().getProxyURI()._isValid()) { - cReqUri.assign(oSuppProxy.ref().getProxyURI().ref().encode()); + cReqUri.assign(ObjectOps.cast(oSuppProxy, IhttpRequest.class).ref().getUri().ref().encode()); } else { @@ -287,7 +286,7 @@ poRequest.ref().getVersion(), chr(13), chr(10)); - ObjectOps.cast(this.getEntity(), ByteBucket.class).ref().putString(new longchar(cMsg)); + bucket().putString(new longchar(cMsg)); })); } @@ -296,10 +295,10 @@ { @LegacyParameter(name = "poRequest", type = "OBJECT", qualified = "openedge.net.http.ihttprequest", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - protected void writeHeaders(final object _poRequest) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + protected void writeHeaders(final object _poRequest) { - object poRequest = TypeFactory.initInput(_poRequest); + object poRequest = TypeFactory.initInput(_poRequest); internalProcedure(DefaultRequestFilter.class, this, "WriteHeaders", new Block((Body) () -> { @@ -325,20 +324,20 @@ { object hdr = headers.get()[i]; character cMsg = TextOps.concat(hdr.ref().toLegacyString(), chr(13), chr(10)); - ObjectOps.cast(this.getEntity(), ByteBucket.class).ref().putString(new longchar(cMsg)); + bucket().putString(new longchar(cMsg)); } if (!poRequest.ref().hasHeader(new character("Accept")).booleanValue()) { character cMsg = TextOps.concat("Accept: */*", chr(13), chr(10)); - ObjectOps.cast(this.getEntity(), ByteBucket.class).ref().putString(new longchar(cMsg)); + bucket().putString(new longchar(cMsg)); } if (poRequest.ref().getTransferEncoding().getValue() != TransferEncodingEnum.none.ref().toLegacyString().getValue()) { character cMsg = TextOps.concat("Accept-Encoding: ", TextOps.toLowerCase(poRequest.ref().getTransferEncoding()), chr(13), chr(10)); - ObjectOps.cast(this.getEntity(), ByteBucket.class).ref().putString(new longchar(cMsg)); + bucket().putString(new longchar(cMsg)); } })); === modified file 'src/com/goldencode/p2j/oo/net/http/filter/payload/MessageWriter.java' --- src/com/goldencode/p2j/oo/net/http/filter/payload/MessageWriter.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/payload/MessageWriter.java 2020-12-08 12:46:56 +0000 @@ -9,6 +9,7 @@ ** 002 CA 20191024 Added method support levels and updated the class support level. ** 003 ME 20200415 Instantiate logger as needed to avoid invalid handle errors, ** fix error handling/reporting. +** 20201208 Fix entity get/set signature, implement log methods. */ /* @@ -79,7 +80,6 @@ import com.goldencode.p2j.oo.lang.*; import com.goldencode.p2j.oo.logging.*; import com.goldencode.p2j.oo.logging.LogLevelEnum; -import com.goldencode.p2j.oo.net.http.*; import com.goldencode.p2j.util.*; import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; @@ -92,7 +92,7 @@ * */ @LegacyResource(resource = "OpenEdge.Net.HTTP.Filter.Payload.MessageWriter") -@LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL|RT_LVL_PARTIAL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public abstract class MessageWriter extends OutputStream implements ISupportLogging @@ -102,7 +102,7 @@ /** Entity type */ protected final object entityType = TypeFactory.object(LegacyClass.class); /** Entity */ - protected final object entity = TypeFactory.object(BaseObject.class); + protected final object entity = TypeFactory.object(BaseObject.class); /** * Get logger. @@ -183,7 +183,7 @@ qualified = "Progress.Lang.Object", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public void setEntity(object poEntity) + public void setEntity(object poEntity) { internalProcedure(this, "Entity", new Block((Body) () -> { @@ -223,7 +223,7 @@ internalProcedure(this, "__net_http_BuilderRegistry_constructor__", new Block((Body) () -> { __io_OutputStream_constructor__(); - assertNotNull(poType, "EntityType"); + assertNotNull(poType, "Entity type"); this.entityType.assign(poType); })); } @@ -244,10 +244,10 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_http_filter_payload_MessageWriter_constructor__( object _poType, - object _poEntity) + object _poEntity) { object poType = TypeFactory.initInput(_poType); - object poEntity = TypeFactory.initInput(_poEntity); + object poEntity = TypeFactory.initInput(_poEntity); internalProcedure(this, "__net_http_BuilderRegistry_constructor__", new Block((Body) () -> { __net_http_filter_payload_MessageWriter_constructor__(poType); @@ -408,11 +408,18 @@ @LegacyParameter(name = "poLoglevel", type = "OBJECT", qualified = "OpenEdge.Logging.LogLevelEnum", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - protected void logMessage(character pcMessage, LogLevelEnum poLoglevel) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + protected void logMessage(character pcMessage, object poLoglevel) { internalProcedure(this, "LogMessage", new Block((Body)() -> { - // TODO: implement + if (poLoglevel._isValid()) + { + logMessage (pcMessage, new integer(poLoglevel.ref()._getValue())); + } + else + { + getLogger().ref().warn(pcMessage); + } })); } @@ -427,11 +434,36 @@ @LegacyParameter(name = "pcMessage", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "piLoglevel", type = "INTEGER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) protected void logMessage(character pcMessage, integer piLoglevel) { internalProcedure(this, "LogMessage", new Block((Body)() -> { - // TODO: implement + long level = piLoglevel.isUnknown() ? LogLevelEnum.warn.ref()._getValue() : piLoglevel.longValue(); + + if (level == LogLevelEnum.fatal.ref()._getValue()) + { + getLogger().ref().fatal(pcMessage); + } + else if (level == LogLevelEnum.error.ref()._getValue()) + { + getLogger().ref().error(pcMessage); + } + else if (level == LogLevelEnum.info.ref()._getValue()) + { + getLogger().ref().info(pcMessage); + } + else if (level == LogLevelEnum.debug.ref()._getValue()) + { + getLogger().ref().debug(pcMessage); + } + else if (level == LogLevelEnum.trace.ref()._getValue()) + { + getLogger().ref().trace(pcMessage); + } + else + { + getLogger().ref().warn(pcMessage); + } })); } @@ -440,11 +472,22 @@ @LegacyParameter(name = "pStream", type = "OBJECT", qualified = "Progress.IO.FileInputStream", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - protected int64 writeFileStream(object pStream) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + protected int64 writeFileStream(object _pStream) { + object pStream = TypeFactory.initInput(_pStream); + memptr mPtr = TypeFactory.memptr(); + return function(this, "WriteFileStream", int64.class, new Block((Body)() -> { - // TODO: implement + Assert.notNull(pStream, new character("File input stream")); + + + pStream.ref().read(mPtr); + + returnNormal(write(mPtr)); + + }, (Fini)() -> { + mPtr.setLength(0); })); } @@ -465,8 +508,8 @@ */ protected void unsupported(object poData) { - String msg = String.format("Unsupported object type: %s", - poData.getClass().getTypeName()); + String msg = TextOps.substitute("Unsupported object type: &1", + poData.ref().getLegacyClass().ref().getTypeName()).getValue(); undoThrow(AppError.newInstance(msg, 0)); } } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/payload/MultipartBodyWriter.java' --- src/com/goldencode/p2j/oo/net/http/filter/payload/MultipartBodyWriter.java 2021-01-13 15:36:44 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/payload/MultipartBodyWriter.java 2021-01-31 10:14:52 +0000 @@ -8,7 +8,8 @@ ** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD. ** 002 IAS 20190527 Added multipart support. ** 003 CA 20191024 Added method support levels and updated the class support level. -** 004 CA 20210113 Renamed clear() to clear_(), to follow NameConverter's rules. +** 004 MP 20210112 Implement as OE12.2 +** 005 CA 20210113 Renamed clear() to clear_(), to follow NameConverter's rules. */ /* @@ -70,19 +71,23 @@ import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.function; import static com.goldencode.p2j.util.BlockManager.internalProcedure; +import static com.goldencode.p2j.util.BlockManager.onBlockLevel; import static com.goldencode.p2j.util.BlockManager.returnNormal; +import static com.goldencode.p2j.util.BlockManager.undoThrowTopLevel; import java.util.concurrent.atomic.*; -import org.apache.commons.lang3.*; import com.goldencode.p2j.oo.core.*; import com.goldencode.p2j.oo.lang.*; import com.goldencode.p2j.oo.net.*; import com.goldencode.p2j.oo.net.http.*; import com.goldencode.p2j.oo.net.http.filter.writer.*; import com.goldencode.p2j.util.*; +import com.goldencode.p2j.util.BlockManager.Action; +import com.goldencode.p2j.util.BlockManager.Condition; import com.goldencode.p2j.util.InternalEntry.*; + /** * * Write multipart/* body @@ -129,7 +134,6 @@ @Override public void setBoundary(character boundary) { - character pcEncoding = TypeFactory.initInput(boundary); internalProcedure(this, "Boundary", new Block((Body) () -> { this.boundary.assign(boundary); @@ -143,6 +147,7 @@ { externalProcedure(MultipartBodyWriter.this, new Block((Body) () -> { + onBlockLevel(Condition.ERROR, Action.THROW); { } })); @@ -159,8 +164,8 @@ new Block((Body) () -> { __net_http_filter_payload_MessageWriter_constructor__( - ObjectOps.getLegacyClass(ByteBucket.class) - ); + ObjectOps.getLegacyClass(ByteBucket.class)); + setBoundary(SecurityOps.convertUniversalUIDToGlobalUID()); })); } @@ -177,7 +182,7 @@ this.externalEntity.assign(entity.isValid()); if (!externalEntity.booleanValue()) { - entity.assign(ByteBucket.instance().ref()); + entity.assign(ByteBucket.instance()); } })); } @@ -196,34 +201,59 @@ }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override - public int64 write(object poData) - { - return function(this, "Write", int64.class, new Block((Body) () -> - { - object part = TypeFactory.object(ByteBucket.class); + public int64 write(object _poData) + { + object poData = TypeFactory.initInput(_poData); + + return function(this, "Write", int64.class, new Block((Body) () -> + { + + if (!poData._isValid()) + returnNormal(0); + + if (!ObjectOps.typeOf(poData, MultipartEntity.class).booleanValue()) + { + String errMsg = "Unsupported object type: " + poData.ref(). + getLegacyClass().ref().getTypeName().getValue(); + undoThrowTopLevel(AppError.newInstance(errMsg, 0)); + } + + returnNormal(write_1(ObjectOps.cast(poData, MultipartEntity.class))); + })); + } + + @LegacySignature(type = Type.METHOD, name = "Write", parameters = + { + @LegacyParameter(name = "pData", type = "OBJECT", qualified = "openedge.net.multipartentity", mode = "INPUT") + }) + protected int64 write_1(final object _pData) + { + object pData = TypeFactory.initInput(_pData); + return function(this, "Write", int64.class, new Block((Body) () -> + { + Assert.notNull(pData, new character("Multipart entity")); + object mpart = TypeFactory.object(MessagePart.class); - object entity = TypeFactory.object(MultipartEntity.class); object writer = TypeFactory.object(MessageWriter.class); - - Assert.isType(poData, ObjectOps.getLegacyClass(MultipartEntity.class)); - + object part = TypeFactory.object(ByteBucket.class); + long initialSize = bucket().getSize().longValue(); - entity.assign(ObjectOps.cast(poData, MultipartEntity.class)); - this.boundary.assign(entity.ref().getBoundary()); + + this.boundary.assign(pData.ref().getBoundary()); + part = ObjectOps.newInstance(ByteBucket.class); - if (!StringUtils.isEmpty(entity.ref().getPrologue().getValue())) + if (!TextOps.isEmpty(pData.ref().getPrologue().getValue())) { - bucket().putString(new longchar(entity.ref().getPrologue())); + bucket().putString(new longchar(pData.ref().getPrologue())); bucket().putString(new longchar(CRLF)); } - for (int ip = 0; ip < entity.ref().getSize().intValue(); ip++) + + for (int ip = 0; ip < pData.ref().getSize().intValue(); ip++) { part.ref().clear_(); - bucket().putString(new longchar( - String.format("--%s%s", this.boundary.getValue(), CRLF) - )); - mpart.assign(entity.ref().getPart(new integer(ip+1))); + bucket().putString(new longchar(TextOps.concat("--", this.boundary.getValue(), CRLF))); + mpart.assign(pData.ref().getPart(new integer(ip+1))); writer.assign(BodyWriterBuilder.build(mpart).ref().writeTo(part).ref().getWriter()); Assert.notNull(writer, new character("Part writer")); writer.ref().open(); @@ -252,26 +282,26 @@ ).intValue(); for(int hn = nh; hn > 0; hn--) { - bucket().putString(new longchar( - String.format("%s%s", headers.get()[hn-1].ref().toString(), CRLF) - )); + bucket().putString(new longchar(TextOps.concat(headers.get()[hn-1].ref().toLegacyString(), CRLF))); } bucket().putString(new longchar(CRLF)); bucket().putBytes(part); bucket().putString(new longchar(CRLF)); } - bucket().putString(new longchar( - String.format("--%s--%s", this.boundary.getValue(), CRLF) - )); - if (!StringUtils.isEmpty(entity.ref().getEpilogue().getValue())) + bucket().putString(new longchar(TextOps.concat("--", this.boundary, "--", CRLF))); + + if (!TextOps.isEmpty(pData.ref().getEpilogue().getValue())) { - bucket().putString(new longchar(entity.ref().getEpilogue())); + bucket().putString(new longchar(pData.ref().getEpilogue())); } else if (!this.externalEntity.booleanValue()) { bucket().putString(new longchar(CRLF)); } + returnNormal(new int64(bucket().getSize().longValue() - initialSize)); + })); } + } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/payload/XmlBodyWriter.java' --- src/com/goldencode/p2j/oo/net/http/filter/payload/XmlBodyWriter.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/payload/XmlBodyWriter.java 2021-01-31 10:14:52 +0000 @@ -8,6 +8,8 @@ ** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20191024 Added method support levels and updated the class support level. ** 003 MP 20200612 Added missing methods as stubs taken by converting the skeleton using FWD. +** 003 MP 20210112 make write methods work as OE 12.2. Still need attention +** 004 ME 20210131 Fix ctor call for TargetData. */ /* @@ -71,9 +73,14 @@ import static com.goldencode.p2j.util.BlockManager.internalProcedure; import static com.goldencode.p2j.util.BlockManager.onBlockLevel; import static com.goldencode.p2j.util.BlockManager.returnNormal; +import static com.goldencode.p2j.util.BlockManager.undoThrowTopLevel; +import com.goldencode.p2j.oo.common.support.ImemptrHolder; import com.goldencode.p2j.oo.core.*; +import com.goldencode.p2j.oo.io.FileInputStream; import com.goldencode.p2j.oo.lang.*; +import com.goldencode.p2j.persist.TargetData; +import com.goldencode.p2j.persist.serial.Serializator; import com.goldencode.p2j.util.*; import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; @@ -172,7 +179,7 @@ { if (!entity.isValid().booleanValue()) { - entity.assign(ByteBucket.instance().ref()); + entity.assign(ByteBucket.instance()); } })); } @@ -186,10 +193,49 @@ public int64 write(final handle _pData) { handle pData = TypeFactory.initInput(_pData); - return function(XmlBodyWriter.class, this, "Write", int64.class, new Block((Body) () -> { - UnimplementedFeature.missing("XmlBodyWriter:Write h METHOD"); + memptr mResult = TypeFactory.memptr(); + + if (pData._isValid()) + { + if (pData.isType("X-DOCUMENT")) + { + pData.unwrapXDocument().save("memptr", mResult); + encoding.assign(ConvCp.toMime(I18nOps.getCPInternal())); + } + else if (pData.isType("TEMP-TABLE")) + { + pData.unwrapTempTable().writeXml(new TargetData(Serializator.TYPE_MEMPTR, mResult)); + encoding.assign("utf-8"); + } + else if (pData.isType("BUFFER")) + { + pData.unwrapBuffer().writeXml(new TargetData(Serializator.TYPE_MEMPTR, mResult)); + encoding.assign("utf-8"); + } + else if (pData.isType("DATASET")) + { + //TODO: write xml not defined in ProDataSet handle + //pData.unwrapDataSet().writeXml(new TargetData(mResult)); + encoding.assign("utf-8"); + } + else + { + String errMsg = "Unsupported handle type: " + pData.unwrapType().getResourceType().getValue(); + undoThrowTopLevel(AppError.newInstance(errMsg, 0)); + } + } + try + { + bucket().putBytes(mResult); + returnNormal(mResult.length()); + } + finally + { + mResult.setLength(0); + } + })); } @@ -222,12 +268,39 @@ }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override - public int64 write(memptr _pData) + public int64 write(final memptr _pData) { + memptr pData = TypeFactory.initInput(_pData); + return function(this, "Write", int64.class, new Block((Body) () -> { - bucket().putBytes(_pData.getPointerValue(), _pData.length()); - returnNormal(_pData.length()); + if (pData.length().intValue() == 0) + returnNormal(new int64(0)); + + int64 mCheckLength = TypeFactory.int64(10l); + + if (pData.length().intValue() < 10) + mCheckLength = pData.length(); + + character mContent = TypeFactory.initInput(TextOps.trim(pData.getString(1, mCheckLength))); + + if ( !TextOps.begins(mContent, "<").booleanValue() ) + { + String errMsg = "Data does not appear to be XML; starts with \"" + + TextOps.substring(mContent, 1, 10).getValue() + "\""; + undoThrowTopLevel(AppError.newInstance(errMsg, 0)); + } + + try + { + encoding.assign(ConvCp.toMime(I18nOps.getCPInternal())); + bucket().putBytes(pData.getPointerValue(), pData.length()); + returnNormal(pData.length()); + } + finally + { + pData.setLength(0); + } })); } @@ -240,39 +313,63 @@ */ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override - public int64 write(object poData) + public int64 write(object _poData) { - handle doc = TypeFactory.handle(); - memptr xml = TypeFactory.memptr(); - character charset = TypeFactory.character(); - - Assert.notNull(poData, new character("XML payload")); - if (ObjectOps.typeOf(poData, WidgetHandle.class).booleanValue()) - { - doc.assign(ObjectOps.cast(poData, WidgetHandle.class).ref().getValue()); - charset.assign(ConvCp.toMime(doc.unwrapXDocument().getEncoding())); - doc.unwrapXDocument().save(new character("memptr"), xml); - } - else if (ObjectOps.typeOf(poData, LegacyClass.class).booleanValue()) - { - object str = ObjectOps.cast(poData, LegacyString.class); - charset.assign(ConvCp.toMime(str.ref().getEncoding())); - new LobCopy( - new SourceLob(str.ref().getValue()), - new TargetLob(xml)).run(); - } - else - { - unsupported(poData); - } - try - { - this.encoding.assign(charset); - bucket().putBytes(xml.getPointerValue(), xml.length()); - return xml.length(); - } - finally { - xml.setLength(0); - } + object poData = TypeFactory.initInput(_poData); + + return function(this, "Write", int64.class, new Block((Body) () -> { + + if (!poData._isValid()) + returnNormal(0); + + memptr xml = TypeFactory.memptr(); + character charset = TypeFactory.character(); + + if (ObjectOps.typeOf(poData, WidgetHandle.class).booleanValue()) + { + returnNormal(this.write(ObjectOps.cast(poData, WidgetHandle.class).ref().getValue())); + } + else if (ObjectOps.typeOf(poData, LegacyClass.class).booleanValue()) + { + object str = ObjectOps.cast(poData, LegacyString.class); + charset.assign(ConvCp.toMime(str.ref().getEncoding())); + new LobCopy(new SourceLob(str.ref().getValue()), new TargetLob(xml)).run(); + } + else if (ObjectOps.typeOf(poData, ImemptrHolder.class).booleanValue()) + { + returnNormal(this.write(ObjectOps.cast(poData, ImemptrHolder.class).ref().getValue())); + } + else if (ObjectOps.typeOf(poData, FileInputStream.class).booleanValue()) + { + object oFis = ObjectOps.newInstance(FileInputStream.class); + + oFis.assign(ObjectOps.cast(poData, FileInputStream.class)); + + String[] result = TextOps.splitInt(oFis.ref().getFileName().getValue(), '.'); + + if (result[result.length - 1].equalsIgnoreCase("xml") || result[result.length - 1].equalsIgnoreCase("xsd")) + { + returnNormal(this.writeFileStream(oFis)); + } + String errMsg = "Unsupported file extension ." + result[result.length - 1] + " for XML"; + undoThrowTopLevel(AppError.newInstance(errMsg, 0)); + + } + else + { + unsupported(poData); + } + try + { + this.encoding.assign(charset); + bucket().putBytes(xml.getPointerValue(), xml.length()); + returnNormal(xml.length()); + } + finally + { + xml.setLength(0); + } + + })); } } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/writer/AuthenticationRequestWriterBuilder.java' --- src/com/goldencode/p2j/oo/net/http/filter/writer/AuthenticationRequestWriterBuilder.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/writer/AuthenticationRequestWriterBuilder.java 2020-11-06 09:44:58 +0000 @@ -8,6 +8,7 @@ ** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20191024 Added method support levels and updated the class support level. ** 003 MP 20200611 Added missing methods as stubs taken by converting the skeleton using FWD. +** 004 ME 20201106 Implement all methods as per OE12.2. */ /* @@ -72,6 +73,8 @@ import static com.goldencode.p2j.util.BlockManager.onBlockLevel; import static com.goldencode.p2j.util.BlockManager.returnNormal; +import com.goldencode.p2j.oo.core.Assert; +import com.goldencode.p2j.oo.core.ISupportInitialize; import com.goldencode.p2j.oo.lang.*; import com.goldencode.p2j.oo.net.http.*; import com.goldencode.p2j.oo.net.http.filter.auth.*; @@ -87,14 +90,12 @@ * */ @LegacyResource(resource = "OpenEdge.Net.HTTP.Filter.Writer.AuthenticationRequestWriterBuilder") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_PARTIAL) -public class AuthenticationRequestWriterBuilder -extends BaseObject +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) +public class AuthenticationRequestWriterBuilder extends BaseObject { - + /** Builder registry */ - private static ContextLocal> REGISTRY = - new ContextLocal>() + private static ContextLocal> REGISTRY = new ContextLocal>() { /** * Create initial value. @@ -102,78 +103,99 @@ @Override protected object initialValue() { - object registry = - UndoableFactory.object(BuilderRegistry.class); - registry.assign(ObjectOps.newInstance(BuilderRegistry.class, "I", ObjectOps.getLegacyClass(IHttpMessageWriter.class))); - initializeRegistry(registry); - return registry; + return TypeFactory.object(BuilderRegistry.class); } }; - + public void __net_http_filter_writer_AuthenticationRequestWriterBuilder_execute__() { - externalProcedure(AuthenticationRequestWriterBuilder.class, AuthenticationRequestWriterBuilder.this, new Block((Init) () -> - { - ObjectOps.register(REGISTRY); - }, - (Body) () -> - { - onBlockLevel(Condition.ERROR, Action.THROW); - { - } - })); + externalProcedure(AuthenticationRequestWriterBuilder.class, + AuthenticationRequestWriterBuilder.this, new Block((Init) () -> { + ObjectOps.register(REGISTRY); + }, (Body) () -> { + onBlockLevel(Condition.ERROR, Action.THROW); + { + } + })); } @LegacySignature(type = Type.CONSTRUCTOR) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public void __net_http_filter_writer_AuthenticationRequestWriterBuilder_constructor__() { - internalProcedure(AuthenticationRequestWriterBuilder.class, this, "__net_http_filter_writer_AuthenticationRequestWriterBuilder_constructor__", new Block((Body) () -> - { - __lang_BaseObject_constructor__(); - })); + internalProcedure(AuthenticationRequestWriterBuilder.class, this, + "__net_http_filter_writer_AuthenticationRequestWriterBuilder_constructor__", + new Block((Body) () -> { + __lang_BaseObject_constructor__(); + })); } - + @LegacySignature(type = Type.CONSTRUCTOR) - public void __net_http_filter_writer_AuthenticationRequestWriterBuilder_constructor__static__() + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public static void __net_http_filter_writer_AuthenticationRequestWriterBuilder_constructor__static__() { - externalProcedure(AuthenticationRequestWriterBuilder.class, new Block((Body) () -> - { + externalProcedure(AuthenticationRequestWriterBuilder.class, new Block((Body) () -> { onBlockLevel(Condition.ERROR, Action.THROW); })); } - - @LegacySignature(type = Type.METHOD, name = "Build", qualified = "openedge.net.http.ihttpmessagewriter", parameters = - { - @LegacyParameter(name = "poRequest", type = "OBJECT", qualified = "openedge.net.http.iauthenticatedrequest", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public static object build(final object _poRequest) - { - object poRequest = TypeFactory.initInput(_poRequest); - + + @LegacySignature(type = Type.METHOD, name = "Build", qualified = "openedge.net.http.ihttpmessagewriter", parameters = { + @LegacyParameter(name = "poRequest", type = "OBJECT", qualified = "openedge.net.http.iauthenticatedrequest", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public static object build( + final object _poRequest) + { + object poListeners[] = TypeFactory + .objectExtent(IauthFilterEventHandler.class); + return function(AuthenticationRequestWriterBuilder.class, "Build", object.class, new Block((Body) () -> { - UnimplementedFeature.missing("AuthenticationRequestWriterBuilder:Build METHOD"); + returnNormal(build(_poRequest, poListeners)); })); } - @LegacySignature(type = Type.METHOD, name = "Build", qualified = "openedge.net.http.ihttpmessagewriter", parameters = - { - @LegacyParameter(name = "poRequest", type = "OBJECT", qualified = "openedge.net.http.iauthenticatedrequest", mode = "INPUT"), - @LegacyParameter(name = "poListener", type = "OBJECT", extent = -1, qualified = "openedge.net.http.filter.auth.iauthfiltereventhandler", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public static object build(final object _poRequest, final object[] _poListener) - { - object poRequest = TypeFactory.initInput(_poRequest); - object[] poListener[] = new object[][] - { - TypeFactory.initInput(_poListener) - }; - + @LegacySignature(type = Type.METHOD, name = "Build", qualified = "openedge.net.http.ihttpmessagewriter", parameters = { + @LegacyParameter(name = "poRequest", type = "OBJECT", qualified = "openedge.net.http.iauthenticatedrequest", mode = "INPUT"), + @LegacyParameter(name = "poListeners", type = "OBJECT", extent = -1, qualified = "openedge.net.http.filter.auth.iauthfiltereventhandler", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public static object build( + final object _poRequest, + final object[] _poListeners) + { + object poRequest = TypeFactory + .initInput(_poRequest); + object poListeners[] = TypeFactory + .initInput(_poListeners); + return function(AuthenticationRequestWriterBuilder.class, "Build", object.class, new Block((Body) () -> { - UnimplementedFeature.missing("AuthenticationRequestWriterBuilder:Build 2 METHOD"); + Assert.notNull(poRequest, new character("Request")); + + object writer = TypeFactory + .object(AuthenticationRequestFilter.class); + + object writerCls = getRegistry().ref() + .get(poRequest.ref().getAuthenticationMethod()); + + if (!writerCls.isUnknown()) + { + Assert.isType(writerCls, + ObjectOps.getLegacyClass(AuthenticationRequestFilter.class)); + + writer.assign( + ObjectOps.newInstance(writerCls.ref().getType(), "I", poRequest)); + + if (writer._isValid() && writer.ref() instanceof ISupportInitialize) + ((ISupportInitialize) writer.ref()).initialize(); + + for (object listener : poListeners) + { + writer.ref().subscribeListener(listener); + } + } + + returnNormal(writer); + })); } @@ -183,36 +205,26 @@ * @return registry. */ @LegacySignature(type = Type.GETTER, name = "Registry") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public static object getRegistry() { - return function(null, "Registry", object.class, new Block((Body) () -> - { - returnNormal(REGISTRY.get()); - })); - } - - /** - * Initialize registry. - * - * @param _poRegistry to be initialized. - */ - @LegacySignature(type = Type.METHOD, name = "InitializeRegistry", parameters = - { - @LegacyParameter(name = "poRegistry", type = "OBJECT", - qualified = "openedge.net.http.builderregistry", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public static void initializeRegistry(final object _poRegistry) - { - internalProcedure(null, "InitializeRegistry", new Block((Body) ()-> { - _poRegistry.ref()._put("Basic", - ObjectOps.getLegacyClass(BasicAuthenticationFilter.class)); - _poRegistry.ref()._put("Digest", - ObjectOps.getLegacyClass(DigestAuthenticationFilter.class)); - _poRegistry.ref()._put("None", - ObjectOps.getLegacyClass(NoAuthenticationFilter.class)); - })); - } - + return function(null, "Registry", object.class, new Block((Body) () -> { + object registry = REGISTRY.get(); + + if (!registry._isValid()) + { + registry.assign(ObjectOps.newInstance(BuilderRegistry.class)); + + registry.ref()._put("Basic", + ObjectOps.getLegacyClass(BasicAuthenticationFilter.class)); + registry.ref()._put("Digest", + ObjectOps.getLegacyClass(DigestAuthenticationFilter.class)); + registry.ref()._put("None", ObjectOps.getLegacyClass(NoAuthenticationFilter.class)); + + REGISTRY.set(registry); + } + + returnNormal(registry); + })); + } } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/writer/BodyWriterBuilder.java' --- src/com/goldencode/p2j/oo/net/http/filter/writer/BodyWriterBuilder.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/writer/BodyWriterBuilder.java 2021-01-28 08:38:48 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20191024 Added method support levels and updated the class support level. +** 003 MP 20201218 Implement as of OE12.2. */ /* @@ -92,7 +93,8 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public static void __net_http_filter_writer_BodyWriterBuilder_constructor__static__() { - externalProcedure(BodyWriterBuilder.class, new Block((Body) () -> { + externalProcedure(BodyWriterBuilder.class, new Block((Body) () -> + { onBlockLevel(Condition.ERROR, Action.THROW); })); } @@ -111,24 +113,38 @@ }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static object build( - object poPart) + object _poPart) { + object poPart = TypeFactory.initInput(_poPart); return function(null, "Build", object.class, new Block((Body)() -> { + if (!poPart.ref().getHeaders().ref().has(new character("Content-Type")).booleanValue()) { ErrorManager.recordOrThrowError(0, "Message Content-Type header cannot be null", false, true); } + object contentType = TypeFactory.object(HttpHeader.class); + contentType.assign(poPart.ref().getHeaders().ref().get(new character("Content-Type"))); - returnNormal( - build(poPart.ref().getContentType()). - ref().option(new character("encodedAs"), - contentType.ref().getParameterValue(new character("charset"))). - ref().option(new character("multipartBoundary"), - contentType.ref().getParameterValue(new character("boundary"))) - ); + + object oMWB = TypeFactory.object(MessageWriterBuilder.class); + + oMWB.assign(BodyWriterBuilder.build(poPart.ref().getContentType())); + + if (contentType.ref().hasParameter(new character("charset")).booleanValue()) + { + oMWB.ref().option(new character("encodedAs"), contentType.ref().getParameterValue(new character("charset"))); + } + + if (contentType.ref().hasParameter(new character("boundary")).booleanValue()) + { + oMWB.ref().option(new character("multipartBoundary"), contentType.ref().getParameterValue(new character("boundary"))); + } + + returnNormal(oMWB); + })); } @@ -149,20 +165,23 @@ object _poMessage) { object poMessage = TypeFactory.initInput(_poMessage); - return function(null, "Build", object.class, new Block((Body)() -> { + + return function(null, "Build", object.class, new Block((Body)() -> + { if (!poMessage.ref().hasHeader(new character("Content-Type")).booleanValue()) { ErrorManager.recordOrThrowError(0, "Message Content-Type header cannot be null", false, true); } + object contentType = TypeFactory.object(HttpHeader.class); + + contentType.assign(poMessage.ref().getHeader(new character("Content-Type"))); + object oMsgWrtBld = TypeFactory.object(MessageWriterBuilder.class); - - object po = poMessage; - contentType.assign(poMessage.ref().getHeader(new character("Content-Type"))); - character aa = new character(po.ref().getContentType()); - oMsgWrtBld.assign(BodyWriterBuilder.build(aa)); + + oMsgWrtBld.assign(BodyWriterBuilder.build(poMessage.ref().getContentType())); if (contentType.ref().hasParameter(new character("charset")).booleanValue()) { @@ -190,9 +209,12 @@ @LegacyParameter(name = "pcContentType", type = "CHARACTER", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public static object build(character pcContentType) + public static object build(character _pcContentType) { - return function(null, "Build", object.class, new Block((Body)() -> { + character pcContentType = TypeFactory.initInput(_pcContentType); + + return function(null, "Build", object.class, new Block((Body)() -> + { returnNormal(MessageWriterBuilder.build(pcContentType, BodyWriterRegistry.getRegistry())); })); } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/writer/BodyWriterRegistry.java' --- src/com/goldencode/p2j/oo/net/http/filter/writer/BodyWriterRegistry.java 2020-06-15 00:40:59 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/writer/BodyWriterRegistry.java 2021-01-28 08:38:48 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20191024 Added method support levels and updated the class support level. +** 003 MP 20201218 Implement as of OE12.2. */ /* @@ -95,9 +96,13 @@ protected object initialValue() { object registry = - UndoableFactory.object(BuilderRegistry.class); - registry.assign(ObjectOps.newInstance(BuilderRegistry.class, "I", ObjectOps.getLegacyClass(MessageWriter.class))); + UndoableFactory.object(BuilderRegistry.class); + + registry.assign(ObjectOps.newInstance(BuilderRegistry.class, "I", + ObjectOps.getLegacyClass(MessageWriter.class))); + initializeRegistry(registry); + return registry; } }; @@ -158,6 +163,7 @@ _poRegistry.ref()._put("application/x-www-form-urlencoded", ObjectOps.getLegacyClass(FormDataBodyWriter.class)); _poRegistry.ref()._put("multipart/*", ObjectOps.getLegacyClass(MultipartBodyWriter.class)); + _poRegistry.ref()._put("multipart/form-data", ObjectOps.getLegacyClass(MultipartFormBodyWriter.class)); _poRegistry.ref()._put("text/*", ObjectOps.getLegacyClass(StringBodyWriter.class)); _poRegistry.ref()._put("text/html", ObjectOps.getLegacyClass(HtmlBodyWriter.class)); })); === modified file 'src/com/goldencode/p2j/oo/net/http/filter/writer/DefaultMessageWriterBuilder.java' --- src/com/goldencode/p2j/oo/net/http/filter/writer/DefaultMessageWriterBuilder.java 2020-06-15 00:40:59 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/writer/DefaultMessageWriterBuilder.java 2021-01-28 08:38:48 +0000 @@ -8,6 +8,8 @@ ** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20191024 Added method support levels and updated the class support level. ** 003 ME 20200413 Use the ISupportEncoding interface from Net package. +** 004 MP 20201218 Implement as of OE12.2. +** 20210104 clean code of unused assert */ /* @@ -68,12 +70,9 @@ import static com.goldencode.p2j.util.BlockManager.externalProcedure; import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.function; -import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.internalProcedure; -import static com.goldencode.p2j.report.ReportConstants.*; +import static com.goldencode.p2j.util.BlockManager.onBlockLevel; import static com.goldencode.p2j.util.BlockManager.returnNormal; -import static com.goldencode.p2j.report.ReportConstants.*; - import com.goldencode.p2j.oo.core.*; import com.goldencode.p2j.oo.lang.*; import com.goldencode.p2j.oo.net.*; @@ -81,6 +80,8 @@ import com.goldencode.p2j.oo.net.http.*; import com.goldencode.p2j.oo.net.http.filter.payload.*; import com.goldencode.p2j.util.*; +import com.goldencode.p2j.util.BlockManager.Action; +import com.goldencode.p2j.util.BlockManager.Condition; import com.goldencode.p2j.util.InternalEntry.*; /** @@ -100,6 +101,7 @@ { externalProcedure(DefaultMessageWriterBuilder.this, new Block((Body) () -> { + onBlockLevel(Condition.ERROR, Action.THROW); { } })); @@ -121,8 +123,7 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_http_filter_writer_DefaultMessageWriterBuilder_constructor__( character pcContentType, - object poRegistry - ) + object poRegistry) { internalProcedure(this, "__net_http_filter_writer_DefaultMessageWriterBuilder_constructor__", new Block((Body) () -> @@ -144,18 +145,19 @@ public object getWriter() { return function(this, "Writer", object.class, new Block((Body)() -> { + object writer = TypeFactory.object(MessageWriter.class); object writerType = TypeFactory.object(LegacyClass.class); character entityType = TypeFactory.character(); object entity = TypeFactory.object(BaseObject.class); writerType.assign(getWriter(this.contentType)); + if (!writerType.isValid().booleanValue()) { returnNormal(writer); } - Assert.isType(writerType, ObjectOps.getLegacyClass(MessageWriter.class)); - + writer.assign(ObjectOps.newDynamicInstance(writerType.ref().getTypeName())); if (hasOption(new character("entity")).booleanValue()) === modified file 'src/com/goldencode/p2j/oo/net/http/filter/writer/EntityWriterBuilder.java' --- src/com/goldencode/p2j/oo/net/http/filter/writer/EntityWriterBuilder.java 2019-10-24 23:19:26 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/writer/EntityWriterBuilder.java 2021-01-28 08:38:48 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20191024 Added method support levels and updated the class support level. +** 003 MP 20201218 Implement as of OE12.2. */ /* @@ -101,17 +102,16 @@ }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static object build( - object poPart) + object _poPart) { + object poPart = TypeFactory.initInput(_poPart); + return function(null, "Build", object.class, new Block((Body)() -> { - if (!poPart.ref().getHeaders().ref().has(new character("Content-Type")).booleanValue()) - { - ErrorManager.recordOrThrowError(0, - "Message part Content-Type header cannot be null", - false, true); - } + object contentType = TypeFactory.object(HttpHeader.class); + contentType.assign(poPart.ref().getHeaders().ref().get(new character("Content-Type"))); + returnNormal( build(poPart.ref().getContentType()). ref().option(new character("encodedAs"), @@ -136,15 +136,17 @@ }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static object build_1( - object poMessage) + object _poMessage) { - return function(null, "Build", object.class, new Block((Body)() -> { - if (!poMessage.ref().hasHeader(new character("Content-Type")).booleanValue()) - { - returnNormal(new object<>()); - } + object poMessage = TypeFactory.initInput(_poMessage); + + return function(null, "Build", object.class, new Block((Body)() -> + { + object contentType = TypeFactory.object(HttpHeader.class); + contentType.assign(poMessage.ref().getHeader(new character("Content-Type"))); + returnNormal( build(poMessage.ref().getContentType()). ref().option(new character("encodedAs"), @@ -167,9 +169,12 @@ @LegacyParameter(name = "pcContentType", type = "CHARACTER", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public static object build(character pcContentType) + public static object build(character _pcContentType) { - return function(null, "Build", object.class, new Block((Body)() -> { + character pcContentType = TypeFactory.initInput(_pcContentType); + + return function(null, "Build", object.class, new Block((Body)() -> + { returnNormal(MessageWriterBuilder.build(pcContentType, EntityWriterRegistry.getRegistry())); })); } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/writer/EntityWriterRegistry.java' --- src/com/goldencode/p2j/oo/net/http/filter/writer/EntityWriterRegistry.java 2020-06-15 00:40:59 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/writer/EntityWriterRegistry.java 2021-01-28 08:38:48 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20191024 Added method support levels and updated the class support level. +** 003 MP 20201218 Implement as of OE12.2. */ /* @@ -161,6 +162,7 @@ _poRegistry.ref()._put("text/xml-external-parsed-entity", handlerCls); _poRegistry.ref()._put("multipart/*", ObjectOps.getLegacyClass(MultipartEntityWriter.class)); + _poRegistry.ref()._put("multipart/form-data", ObjectOps.getLegacyClass(MultipartFormEntityWriter.class)); _poRegistry.ref()._put("text/*", ObjectOps.getLegacyClass(StringEntityWriter.class)); })); === modified file 'src/com/goldencode/p2j/oo/net/http/filter/writer/MessageWriterBuilder.java' --- src/com/goldencode/p2j/oo/net/http/filter/writer/MessageWriterBuilder.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/writer/MessageWriterBuilder.java 2021-01-28 08:38:48 +0000 @@ -8,6 +8,8 @@ ** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20191024 Added method support levels and updated the class support level. ** 003 MP 20200611 Modify methods to match converting code signature. +** 20201218 Implement as of OE12.2. +** */ /* @@ -72,8 +74,6 @@ import static com.goldencode.p2j.util.BlockManager.onBlockLevel; import static com.goldencode.p2j.util.BlockManager.returnNormal; -import org.apache.commons.lang3.*; - import com.goldencode.p2j.oo.core.*; import com.goldencode.p2j.oo.lang.*; import com.goldencode.p2j.oo.net.http.*; @@ -111,8 +111,7 @@ TypeFactory.object(BuilderRegistry.class); registry.assign(ObjectOps.newInstance(BuilderRegistry.class, "I", ObjectOps.getLegacyClass(MessageWriterBuilder.class))); - initializeRegistry(registry); - object ss = registry; + initializeRegistry(registry); return registry; } }; @@ -131,8 +130,8 @@ */ public void __net_http_filter_writer_MessageWriterBuilder_execute__() { - externalProcedure(MessageWriterBuilder.this, new Block((Body) () -> - { + externalProcedure(MessageWriterBuilder.this, new Block((Body) () -> { + onBlockLevel(Condition.ERROR, Action.THROW); { } @@ -154,13 +153,12 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_http_filter_writer_MessageWriterBuilder_constructor__( character _pcContentType, - object poRegistry - ) + object poRegistry) { character pcContentType = TypeFactory.initInput(_pcContentType); internalProcedure(this, "__net_http_filter_writer_MessageWriterBuilder_constructor__", - new Block((Body) () -> - { + new Block((Body) () -> { + Assert.notNull(pcContentType, new character("Content type")); Assert.notNull(poRegistry, new character("Writer registry")); __net_http_ConfigBuilder_constructor__(); @@ -174,6 +172,7 @@ public static void __net_http_filter_writer_MessageWriterBuilder_constructor__static__() { externalProcedure(MessageWriterBuilder.class, new Block((Body) () -> { + onBlockLevel(Condition.ERROR, Action.THROW); })); } @@ -187,8 +186,8 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static object getRegistry() { - return function(BodyWriterRegistry.class, "Registry", object.class, new Block((Body) () -> - { + return function(BodyWriterRegistry.class, "Registry", object.class, new Block((Body) () -> { + returnNormal(REGISTRY.get()); })); } @@ -207,6 +206,7 @@ { internalProcedure(null, "InitializeRegistry", new Block((Body) ()-> { + _poRegistry.ref().put(new character(ObjectOps.getLegacyName(MessageWriterBuilder.class)), ObjectOps.getLegacyClass(DefaultMessageWriterBuilder.class)); })); @@ -222,8 +222,8 @@ protected object getWriterRegistry() { return function(BodyWriterRegistry.class, "WriterRegistry", object.class, - new Block((Body) () -> - { + new Block((Body) () -> { + returnNormal(this.writerRegistry); })); } @@ -247,8 +247,8 @@ protected character getContentType() { return function(BodyWriterRegistry.class, "ContentType", character.class, - new Block((Body) () -> - { + new Block((Body) () -> { + returnNormal(this.contentType); })); } @@ -272,6 +272,7 @@ object poRegistry) { return function(null, "Build", object.class, new Block((Body)() -> { + object contentType = TypeFactory.object(HttpHeader.class); contentType.assign(poMessage.ref().getHeader(new character("Content-Type"))); returnNormal( @@ -304,7 +305,7 @@ character pcContentType = TypeFactory.initInput(_pcContentType); return function(null, "Build", object.class, new Block((Body)() -> { - Assert.notNull(pcContentType, new character("ContentType")); + Assert.notNull(pcContentType, new character("Content type")); Assert.notNull(poRegistry, new character("Writer registry")); object builderType = TypeFactory.object(LegacyClass.class); @@ -342,6 +343,7 @@ { object poEntity = TypeFactory.initInput(_poEntity); return function(this, "WriteTo", object.class, new Block((Body)() -> { + Assert.notNull(poEntity, new character("Message Body")); setOption(new character("entity"), poEntity); setOption(new character("entityType"), @@ -369,6 +371,7 @@ character pcName = TypeFactory.initInput(_pcName); character value = TypeFactory.initInput(_pcValue); return function(this, "Option", object.class, new Block((Body)() -> { + Assert.notNullOrEmpty(pcName, new character("Option name")); setOption(pcName, value); returnNormal(new object<>(this)); @@ -397,6 +400,7 @@ object value = TypeFactory.initInput(_poValue); return function(this, "Option", object.class, new Block((Body)() -> { + Assert.notNullOrEmpty(pcName, new character("Option name")); setOption(pcName, value); returnNormal(new object<>(this)); @@ -422,6 +426,7 @@ character pcName = TypeFactory.initInput(_pcName); int64 value = TypeFactory.initInput(_piValue); return function(this, "Option", object.class, new Block((Body)() -> { + Assert.notNullOrEmpty(pcName, new character("Option name")); setOption(pcName, new decimal(value)); returnNormal(new object<>(this)); @@ -447,6 +452,7 @@ character pcName = TypeFactory.initInput(_pcName); decimal value = TypeFactory.initInput(_pdValue); return function(this, "Option", object.class, new Block((Body)() -> { + Assert.notNullOrEmpty(pcName, new character("Option name")); setOption(pcName, value); returnNormal(new object<>(this)); @@ -472,6 +478,7 @@ character pcName = TypeFactory.initInput(_pcName); logical value = TypeFactory.initInput(_plValue); return function(this, "Option", object.class, new Block((Body)() -> { + Assert.notNullOrEmpty(pcName, new character("Option name")); setOption(pcName, value); returnNormal(new object<>(this)); @@ -501,27 +508,28 @@ { character pcContentType = TypeFactory.initInput(_pcContentType); return function(this, "GetWriter", object.class, new Block((Body)() -> { + Assert.notNull(pcContentType, new character("Content type")); + object writer = TypeFactory.object(LegacyClass.class); - if (StringUtils.isEmpty(pcContentType.getValue())) + + if (TextOps.isEmpty(pcContentType.getValue())) { returnNormal(writer); } + String contentType = pcContentType.getValue(); int pp = contentType.indexOf(';'); if (pp >= 0) { contentType = contentType.substring(0, pp); } - String type = contentType; - String subtype = ""; - int ps = contentType.indexOf('/'); - if (ps >=0) - { - type = contentType.substring(0, ps); - subtype = contentType.substring(ps + 1); - } + + String type = TextOps.entry(1, contentType, "/").getValue(); + String subtype = TextOps.entry(2, contentType, "/").getValue(); + writer.assign(this.writerRegistry.ref().get(new character(contentType))); + if (!writer.isValid().booleanValue() && subtype.startsWith("vnd.")) { int p = subtype.indexOf('+'); === modified file 'src/com/goldencode/p2j/oo/net/http/filter/writer/RequestWriterBuilder.java' --- src/com/goldencode/p2j/oo/net/http/filter/writer/RequestWriterBuilder.java 2020-06-15 00:40:59 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/writer/RequestWriterBuilder.java 2021-01-28 08:38:48 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 MP 20200603 First version, stubs taken by converting the skeleton using FWD. +** 002 MP 20210105 Add code in Registry and GetWriter methods ** */ @@ -71,9 +72,18 @@ import static com.goldencode.p2j.report.ReportConstants.CVT_LVL_FULL; import static com.goldencode.p2j.report.ReportConstants.RT_LVL_STUB; +import static com.goldencode.p2j.report.ReportConstants.RT_LVL_FULL; import static com.goldencode.p2j.util.BlockManager.*; import static com.goldencode.p2j.util.InternalEntry.Type; +import com.goldencode.p2j.oo.core.Assert; +import com.goldencode.p2j.oo.lang.LegacyClass; +import com.goldencode.p2j.oo.net.http.BuilderRegistry; +import com.goldencode.p2j.oo.net.http.IhttpRequest; +import com.goldencode.p2j.oo.net.http.filter.payload.ConnectRequestFilter; +import com.goldencode.p2j.oo.net.http.filter.payload.DefaultRequestFilter; +import com.goldencode.p2j.oo.net.http.filter.payload.MessageWriter; + /** * Business logic (converted to Java from the 4GL source code * in OpenEdge/Net/HTTP/Filter/Writer/RequestWriterBuilder.cls). @@ -85,31 +95,42 @@ { @LegacySignature(type = Type.PROPERTY, name = "Request") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - private object request = - TypeFactory.object(com.goldencode.p2j.oo.net.http.IhttpRequest.class); + private object request = + TypeFactory.object(IhttpRequest.class); @LegacySignature(type = Type.PROPERTY, name = "Writer") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - private object writer = - TypeFactory.object(com.goldencode.p2j.oo.net.http.filter.payload.MessageWriter.class); + private object writer = + TypeFactory.object(MessageWriter.class); + /** Registry */ @LegacySignature(type = Type.PROPERTY, name = "Registry") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - private static ContextLocal> registry = - new ContextLocal>() + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + private static ContextLocal> REGISTRY = + new ContextLocal>() { - protected object initialValue() + /** + * Initial value. + */ + @Override + protected object initialValue() { - return TypeFactory.object(com.goldencode.p2j.oo.net.http.BuilderRegistry.class); + object registry = + UndoableFactory.object(BuilderRegistry.class); + + registry.assign(ObjectOps.newInstance(BuilderRegistry.class, "I", + ObjectOps.getLegacyClass(MessageWriter.class))); + initializeRegistry(registry); + return registry; } }; - + + /** + * Execute method. + */ public void __net_http_filter_writer_RequestWriterBuilder_execute__() { - externalProcedure(RequestWriterBuilder.class, RequestWriterBuilder.this, new Block((Init) () -> - { - ObjectOps.register(registry, writer, request); - }, + externalProcedure(RequestWriterBuilder.class, RequestWriterBuilder.this, new Block( (Body) () -> { onBlockLevel(Condition.ERROR, Action.THROW); @@ -117,10 +138,15 @@ } })); } - + + /** + * Get request object. + * + * @return request. + */ @LegacySignature(type = Type.GETTER, name = "Request") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public object getRequest() + public object getRequest() { return function(RequestWriterBuilder.class, this, "Request", object.class, new Block((Body) () -> { @@ -128,40 +154,56 @@ })); } + /** + * Get writer object. + * + * @return writer. + */ @LegacySignature(type = Type.GETTER, name = "Writer") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public object getWriter() + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public object getWriter() { return function(RequestWriterBuilder.class, this, "Writer", object.class, new Block((Body) () -> { - returnNormal(writer); + returnNormal(this.newRequestWriter()); })); } + /** + * Get registry. + * + * @return registry. + */ @LegacySignature(type = Type.GETTER, name = "Registry") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public static object getRegistry() + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public static object getRegistry() { ObjectOps.load(RequestWriterBuilder.class); - return function(RequestWriterBuilder.class, "Registry", object.class, new Block((Body) () -> + return function(null, "Registry", object.class, new Block((Body) () -> { - returnNormal(registry.get()); + returnNormal(REGISTRY.get()); })); } - + + /** + * Initialize registry. + * + * @param _poRegistry to be initialized. + */ @LegacySignature(type = Type.METHOD, name = "InitializeRegistry", parameters = { @LegacyParameter(name = "poRegistry", type = "OBJECT", qualified = "openedge.net.http.builderregistry", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - private static void initializeRegistry(final object _poRegistry) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + private static void initializeRegistry(final object _poRegistry) { - object poRegistry = TypeFactory.initInput(_poRegistry); - - internalProcedure(RequestWriterBuilder.class, "InitializeRegistry", new Block((Body) () -> + internalProcedure(null, "InitializeRegistry", new Block((Body) () -> { - UnimplementedFeature.missing("RequestWriterBuilder:InitializeRegistry METHOD"); + _poRegistry.ref().put(new character("HTTP/1.1"), + ObjectOps.getLegacyClass(DefaultRequestFilter.class)); + _poRegistry.ref().put(new character("HTTP/1.1+CONNECT"), + ObjectOps.getLegacyClass(ConnectRequestFilter.class)); })); } @@ -201,6 +243,9 @@ })); } + /** + * Constructor + */ @LegacySignature(type = Type.CONSTRUCTOR) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) public void __net_http_filter_writer_RequestWriterBuilder_constructor__() @@ -210,7 +255,12 @@ __net_http_ConfigBuilder_constructor__(); })); } - + + /** + * Constructor + * + * @param _pRequest IHttpRequest. + */ @LegacySignature(type = Type.CONSTRUCTOR, parameters = { @LegacyParameter(name = "pRequest", type = "OBJECT", qualified = "openedge.net.http.ihttprequest", mode = "INPUT") @@ -228,6 +278,7 @@ (Body) () -> { __net_http_ConfigBuilder_constructor__(); + request.assign(pRequest); })); } @@ -262,17 +313,27 @@ UnimplementedFeature.missing("RequestWriterBuilder:WriteTo METHOD"); })); } - + + /** + * Adds or overwrites writer property + * + * @return the message writer object + */ @LegacySignature(type = Type.METHOD, name = "NewRequestWriter", qualified = "openedge.net.http.filter.payload.messagewriter") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - protected object newRequestWriter() + protected object newRequestWriter() { return function(RequestWriterBuilder.class, this, "NewRequestWriter", object.class, new Block((Body) () -> { - UnimplementedFeature.missing("RequestWriterBuilder:NewRequestWriter METHOD"); + })); } + /** + * get writer type + * + * @return class type of writer + */ @LegacySignature(type = Type.METHOD, name = "GetWriter", qualified = "progress.lang.class", parameters = { @LegacyParameter(name = "pRequest", type = "OBJECT", qualified = "openedge.net.http.ihttprequest", mode = "INPUT"), @@ -280,15 +341,40 @@ }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) protected object getWriter( - final object _pRequest, - final object _pRegistry) + final object _pRequest, + final object _pRegistry) { - object pRequest = TypeFactory.initInput(_pRequest); - object pRegistry = TypeFactory.initInput(_pRegistry); + object pRequest = TypeFactory.initInput(_pRequest); + object pRegistry = TypeFactory.initInput(_pRegistry); return function(RequestWriterBuilder.class, this, "GetWriter", object.class, new Block((Body) () -> { - UnimplementedFeature.missing("RequestWriterBuilder:GetWriter METHOD"); + Assert.notNull(pRegistry, new character("Request writer registry")); + + object oCls = TypeFactory.object(LegacyClass.class); + + if (!pRequest._isValid()) + { + oCls.assign(pRegistry.ref().get(new character("HTTP/1.1"))); + } + + if (!oCls._isValid()) + { + String cKey = pRequest.ref().getVersion() + "+" + pRequest.ref().getMethod(); + oCls.assign(REGISTRY.get().ref().get(new character(cKey.trim()))); + } + + if (!oCls._isValid()) + { + oCls.assign(REGISTRY.get().ref().get(pRequest.ref().getVersion())); + } + + if (!oCls._isValid()) + { + oCls.assign(REGISTRY.get().ref().get(new character("HTTP/1.1"))); + } + + returnNormal(oCls); })); } } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/writer/VoidMessageWriterBuilder.java' --- src/com/goldencode/p2j/oo/net/http/filter/writer/VoidMessageWriterBuilder.java 2020-06-15 00:40:59 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/writer/VoidMessageWriterBuilder.java 2021-01-28 08:38:48 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 MP 20200603 First version, stubs taken by converting the skeleton using FWD. +** 002 MP 20210105 Implement as of OE12.2. ** */ @@ -69,7 +70,7 @@ import com.goldencode.p2j.util.BlockManager.Condition; import static com.goldencode.p2j.report.ReportConstants.CVT_LVL_FULL; -import static com.goldencode.p2j.report.ReportConstants.RT_LVL_STUB; +import static com.goldencode.p2j.report.ReportConstants.RT_LVL_FULL; import static com.goldencode.p2j.util.BlockManager.*; import static com.goldencode.p2j.util.InternalEntry.Type; @@ -78,15 +79,18 @@ * in OpenEdge/Net/HTTP/Filter/Writer/VoidMessageWriterBuilder.cls). */ @LegacyResource(resource = "OpenEdge.Net.HTTP.Filter.Writer.VoidMessageWriterBuilder") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class VoidMessageWriterBuilder extends com.goldencode.p2j.oo.net.http.filter.writer.MessageWriterBuilder { @LegacySignature(type = Type.PROPERTY, name = "Writer") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) private object writer = TypeFactory.object(com.goldencode.p2j.oo.net.http.filter.payload.MessageWriter.class); + /** + * Execute method + */ public void __net_http_filter_writer_VoidMessageWriterBuilder_execute__() { externalProcedure(VoidMessageWriterBuilder.class, VoidMessageWriterBuilder.this, new Block((Init) () -> @@ -101,8 +105,13 @@ })); } + /** + * Create writer + * + * @return created writer + */ @LegacySignature(type = Type.GETTER, name = "Writer") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public object getWriter() { return function(VoidMessageWriterBuilder.class, this, "Writer", object.class, new Block((Body) () -> @@ -110,13 +119,19 @@ returnNormal(writer); })); } - + + /** + * Constructor + * + * @param _pcContentType content type + * @param poRegistry writer registry + */ @LegacySignature(type = Type.CONSTRUCTOR, parameters = { @LegacyParameter(name = "pcContentType", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "poRegistry", type = "OBJECT", qualified = "openedge.net.http.builderregistry", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_http_filter_writer_VoidMessageWriterBuilder_constructor__( final character _pcContentType, final object _poRegistry) @@ -130,8 +145,7 @@ }, (Body) () -> { - UnimplementedFeature.missing("VoidMessageWriterBuilder CONSTRUCTOR"); - //__net_http_filter_writer_MessageWriterBuilder_constructor__(); + __net_http_filter_writer_MessageWriterBuilder_constructor__(pcContentType, poRegistry); })); } } === modified file 'src/com/goldencode/p2j/oo/net/http/lib/ClientLibraryBuilder.java' --- src/com/goldencode/p2j/oo/net/http/lib/ClientLibraryBuilder.java 2020-06-15 00:40:59 +0000 +++ src/com/goldencode/p2j/oo/net/http/lib/ClientLibraryBuilder.java 2021-01-28 09:44:17 +0000 @@ -10,6 +10,7 @@ ** 003 ME 20200410 Add stub for build method. ** 004 CA 20200503 Added stub for ClientLibraryBuilder:SslVerifyHost and Library getter. ** 005 MP 20200525 Populate methods to get full working class +** 006 MP 20210113 Add SupportLevels and test as OE12.2 */ /* @@ -88,7 +89,7 @@ * in skeleton/oo4gl/OpenEdge/Net/HTTP/Lib/ClientLibraryBuilder.cls). */ @LegacyResource(resource = "OpenEdge.Net.HTTP.Lib.ClientLibraryBuilder") -@LegacyResourceSupport(supportLvl = CVT_LVL_PARTIAL | RT_LVL_PARTIAL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public abstract class ClientLibraryBuilder extends ConfigBuilder { @LegacySignature(type = Type.PROPERTY, name = "PROP_SSL_CIPHERS") @@ -109,7 +110,8 @@ protected static final String CLIENTLIBRARYBUILDER = "OpenEdge.Net.HTTP.Lib.ClientLibraryBuilder"; /** Builder registry */ - private static ContextLocal> REGISTRY = new ContextLocal>() + private static ContextLocal> REGISTRY = + new ContextLocal>() { /** * Create initial value. @@ -192,8 +194,17 @@ })); } - @LegacySignature(type = Type.METHOD, name = "AddSslCipher", qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { + /** + * Add a SSLCipher for this library + * + * @param _p1 The SslCipher name to add. + * + * @return ClientLibraryBuilder + */ + @LegacySignature(type = Type.METHOD, name = "AddSslCipher", + qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { @LegacyParameter(name = "p1", type = "CHARACTER", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object addSslCipher(final character _p1) { character p1 = TypeFactory.initInput(_p1); @@ -214,8 +225,17 @@ })); } - @LegacySignature(type = Type.METHOD, name = "AddSslProtocol", qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { + /** + * Add a SSLProtocol for this library + * + * @param _p1 The SslProtocol name to add. + * + * @return ClientLibraryBuilder + */ + @LegacySignature(type = Type.METHOD, name = "AddSslProtocol", + qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { @LegacyParameter(name = "p1", type = "CHARACTER", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object addSslProtocol(final character _p1) { character p1 = TypeFactory.initInput(_p1); @@ -242,8 +262,8 @@ * @return A builder for the requested type. */ @LegacySignature(type = Type.METHOD, name = "Build", qualified = "OpenEdge.Net.HTTP.Lib.ClientLibraryBuilder") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) - public static object build() + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public static object build() { return function(ClientLibraryBuilder.class, "Build", object.class, new Block((Body) () -> { @@ -260,9 +280,19 @@ })); } - @LegacySignature(type = Type.METHOD, name = "Option", qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { + /** + * Add a Option type of character for this library + * + * @param _p1 option name to add. + * @param _p2 option value to add. + * + * @return ClientLibraryBuilder + */ + @LegacySignature(type = Type.METHOD, name = "Option", + qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { @LegacyParameter(name = "p1", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "p2", type = "CHARACTER", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object option(final character _p1, final character _p2) { character p1 = TypeFactory.initInput(_p1); @@ -279,9 +309,19 @@ })); } - @LegacySignature(type = Type.METHOD, name = "Option", qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { + /** + * Add a Option type of decimal for this library + * + * @param _p1 option name to add. + * @param _p2 option value to add. + * + * @return ClientLibraryBuilder + */ + @LegacySignature(type = Type.METHOD, name = "Option", + qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { @LegacyParameter(name = "p1", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "p2", type = "DECIMAL", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object option(final character _p1, final decimal _p2) { character p1 = TypeFactory.initInput(_p1); @@ -298,9 +338,19 @@ })); } - @LegacySignature(type = Type.METHOD, name = "Option", qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { + /** + * Add a Option type of int64 for this library + * + * @param _p1 option name to add. + * @param _p2 option value to add. + * + * @return ClientLibraryBuilder + */ + @LegacySignature(type = Type.METHOD, name = "Option", + qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { @LegacyParameter(name = "p1", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "p2", type = "INT64", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object option(final character _p1, final int64 _p2) { character p1 = TypeFactory.initInput(_p1); @@ -321,9 +371,19 @@ })); } - @LegacySignature(type = Type.METHOD, name = "Option", qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { + /** + * Add a Option type of logical for this library + * + * @param _p1 option name to add. + * @param _p2 option value to add. + * + * @return ClientLibraryBuilder + */ + @LegacySignature(type = Type.METHOD, name = "Option", + qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { @LegacyParameter(name = "p1", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "p2", type = "LOGICAL", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object option(final character _p1, final logical _p2) { character p1 = TypeFactory.initInput(_p1); @@ -340,9 +400,19 @@ })); } - @LegacySignature(type = Type.METHOD, name = "Option", qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { + /** + * Add a Option type of Object for this library + * + * @param _p1 option name to add. + * @param _p2 option value to add. + * + * @return ClientLibraryBuilder + */ + @LegacySignature(type = Type.METHOD, name = "Option", + qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { @LegacyParameter(name = "p1", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "p2", type = "OBJECT", qualified = "progress.lang.object", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object option(final character _p1, final object _p2) { @@ -360,8 +430,17 @@ })); } - @LegacySignature(type = Type.METHOD, name = "ReuseSession", qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { + /** + * Set ReuseSession as option for this library + * + * @param _p1 option logical to add. + * + * @return ClientLibraryBuilder + */ + @LegacySignature(type = Type.METHOD, name = "ReuseSession", + qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { @LegacyParameter(name = "p1", type = "LOGICAL", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object reuseSession(final logical _p1) { logical p1 = TypeFactory.initInput(_p1); @@ -376,9 +455,18 @@ returnNormal(ObjectOps.thisObject()); })); } - - @LegacySignature(type = Type.METHOD, name = "ServerNameIndicator", qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { + + /** + * Set ServerNameIndicator as option for this library + * + * @param _p1 ServerNameIndicator name to add. + * + * @return ClientLibraryBuilder + */ + @LegacySignature(type = Type.METHOD, name = "ServerNameIndicator", + qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { @LegacyParameter(name = "p1", type = "CHARACTER", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object serverNameIndicator(final character _p1) { character p1 = TypeFactory.initInput(_p1); @@ -394,8 +482,17 @@ })); } - @LegacySignature(type = Type.METHOD, name = "SetRequestTimeout", qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { + /** + * Set SetRequestTimeout as option for this library + * + * @param _p1 SetRequestTimeout value to add. + * + * @return ClientLibraryBuilder + */ + @LegacySignature(type = Type.METHOD, name = "SetRequestTimeout", + qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { @LegacyParameter(name = "p1", type = "DECIMAL", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object setRequestTimeout(final decimal _p1) { decimal p1 = TypeFactory.initInput(_p1); @@ -411,8 +508,17 @@ })); } - @LegacySignature(type = Type.METHOD, name = "SetSslCiphers", qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { + /** + * Set SslCiphers as JsonArray object for this library + * + * @param _p1 SslCiphers extent value to add. + * + * @return ClientLibraryBuilder + */ + @LegacySignature(type = Type.METHOD, name = "SetSslCiphers", + qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { @LegacyParameter(name = "p1", type = "CHARACTER", extent = -1, mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object setSslCiphers(final character[] _p1) { character[] p1 = TypeFactory.initInput(_p1); @@ -421,7 +527,8 @@ new Block((Body) () -> { - object arr = ObjectOps.newInstance(JsonArray.class, "I", (Object) p1); + object arr = ObjectOps.newInstance(JsonArray.class); + arr.ref().add(p1); super.setOption(propSslCiphers, arr); @@ -429,8 +536,17 @@ })); } - @LegacySignature(type = Type.METHOD, name = "SetSslProtocols", qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { + /** + * Set SslProtocols as JsonArray object for this library + * + * @param _p1 SslProtocols extent value to add. + * + * @return ClientLibraryBuilder + */ + @LegacySignature(type = Type.METHOD, name = "SetSslProtocols", + qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { @LegacyParameter(name = "p1", type = "CHARACTER", extent = -1, mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object setSslProtocols(final character[] _p1) { character[] p1 = TypeFactory.initInput(_p1); @@ -438,7 +554,8 @@ return function(ClientLibraryBuilder.class, this, "SetSslProtocols", object.class, new Block((Body) () -> { - object arr = ObjectOps.newInstance(JsonArray.class, "I", (Object) p1); + object arr = ObjectOps.newInstance(JsonArray.class); + arr.ref().add(p1); super.setOption(propSslProtocols, arr); @@ -446,10 +563,18 @@ })); } - @LegacySignature(type = Type.METHOD, name = "SslVerifyHost", qualified = "OpenEdge.Net.HTTP.Lib.ClientLibraryBuilder", parameters = { + /** + * Set VerifyHost as logical for this library + * + * @param _p1 VerifyHost logical value to add. + * + * @return ClientLibraryBuilder + */ + @LegacySignature(type = Type.METHOD, name = "SslVerifyHost", + qualified = "OpenEdge.Net.HTTP.Lib.ClientLibraryBuilder", parameters = { @LegacyParameter(name = "p1", mode = "INPUT", type = "LOGICAL") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_STUB) - public object sslVerifyHost( + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public object sslVerifyHost( final logical _p1) { logical p1 = TypeFactory.initInput(_p1); @@ -464,8 +589,18 @@ })); } - @LegacySignature(type = Type.METHOD, name = "UsingLogger", qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { - @LegacyParameter(name = "p1", type = "OBJECT", qualified = "openedge.logging.ilogwriter", mode = "INPUT") }) + /** + * Set Logger as object for this library + * + * @param _p1 Logger object value to add. + * + * @return ClientLibraryBuilder + */ + @LegacySignature(type = Type.METHOD, name = "UsingLogger", + qualified = "openedge.net.http.lib.clientlibrarybuilder", parameters = { + @LegacyParameter(name = "p1", type = "OBJECT", + qualified = "openedge.logging.ilogwriter", mode = "INPUT") }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public object usingLogger( final object _p1) { @@ -481,11 +616,21 @@ returnNormal(ObjectOps.thisObject()); })); } - + + /** + * Get 'library' attribute value. + * + * @return 'library' attribute value. + */ @LegacySignature(type = Type.GETTER, name = "Library") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public abstract object getLibrary(); + /** + * Get 'PROP_SSL_CIPHERS' attribute value. + * + * @return 'PROP_SSL_CIPHERS' attribute value. + */ @LegacySignature(type = Type.GETTER, name = "PROP_SSL_CIPHERS") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) protected character getPropSslCiphers() @@ -496,7 +641,12 @@ returnNormal(propSslCiphers); })); } - + + /** + * Get 'PROP_SSL_HOSTVERIFY' attribute value. + * + * @return 'PROP_SSL_HOSTVERIFY' attribute value. + */ @LegacySignature(type = Type.GETTER, name = "PROP_SSL_HOSTVERIFY") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) protected character getPropSslHostverify() @@ -508,6 +658,11 @@ })); } + /** + * Get 'PROP_SSL_PROTOCOLS' attribute value. + * + * @return 'PROP_SSL_PROTOCOLS' attribute value. + */ @LegacySignature(type = Type.GETTER, name = "PROP_SSL_PROTOCOLS") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) protected character getPropSslProtocols() @@ -519,6 +674,11 @@ })); } + /** + * Get 'PROP_REUSESESSION' attribute value. + * + * @return 'PROP_REUSESESSION' attribute value. + */ @LegacySignature(type = Type.GETTER, name = "PROP_REUSESESSION") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) protected character getPropReusesession() @@ -530,6 +690,11 @@ })); } + /** + * Get 'PROP_SERVERNAME' attribute value. + * + * @return 'PROP_SERVERNAME' attribute value. + */ @LegacySignature(type = Type.GETTER, name = "PROP_SERVERNAME") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) protected character getPropServername() === modified file 'src/com/goldencode/p2j/oo/net/http/lib/sockets/LegacySocketLibrary.java' --- src/com/goldencode/p2j/oo/net/http/lib/sockets/LegacySocketLibrary.java 2020-09-12 14:11:22 +0000 +++ src/com/goldencode/p2j/oo/net/http/lib/sockets/LegacySocketLibrary.java 2021-01-31 10:14:52 +0000 @@ -10,7 +10,9 @@ ** 003 CA 20191024 Added method support levels and updated the class support level. ** 004 IAS 20191108 Added HTTP Redirect support. ** 005 MP 20200602 Add STUB constructors, properties and methods requested by calls made -** by LegacySocketLibraryBuilder class +** by LegacySocketLibraryBuilder class. +** 006 ME 20210128 Add query parameters and fragment when executing request. +** 20210130 Fix call to 'next' iterator method. */ /* @@ -74,10 +76,10 @@ import static com.goldencode.p2j.util.BlockManager.internalProcedure; import static com.goldencode.p2j.util.BlockManager.onBlockLevel; import static com.goldencode.p2j.util.BlockManager.returnNormal; -import static com.goldencode.p2j.report.ReportConstants.*; import java.io.*; import java.net.*; +import java.nio.charset.Charset; import java.security.*; import java.security.cert.*; import java.util.*; @@ -92,6 +94,8 @@ import org.apache.http.HttpResponse; import org.apache.http.ProtocolException; import org.apache.http.client.*; +import org.apache.http.client.config.CookieSpecs; +import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.*; import org.apache.http.client.methods.*; import org.apache.http.client.utils.*; @@ -102,28 +106,27 @@ import org.apache.http.impl.client.*; import org.apache.http.impl.conn.*; import org.apache.http.protocol.*; -import org.apache.http.ssl.*; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.ssl.TrustStrategy; import org.apache.http.util.*; import com.goldencode.p2j.directory.*; import com.goldencode.p2j.oo.core.*; +import com.goldencode.p2j.oo.core.collections.IStringStringMap; +import com.goldencode.p2j.oo.core.collections.Iiterator; import com.goldencode.p2j.oo.json.objectmodel.*; import com.goldencode.p2j.oo.lang.*; import com.goldencode.p2j.oo.logging.ISupportLogging; -import com.goldencode.p2j.oo.logging.IlogWriter; +import com.goldencode.p2j.oo.logging.VoidLogger; import com.goldencode.p2j.oo.net.*; import com.goldencode.p2j.oo.net.http.*; import com.goldencode.p2j.oo.net.http.filter.payload.*; import com.goldencode.p2j.oo.net.http.filter.writer.*; -import com.goldencode.p2j.oo.net.http.lib.sockets.*; import com.goldencode.p2j.security.*; import com.goldencode.p2j.util.*; import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; import com.goldencode.p2j.util.InternalEntry.*; -import com.goldencode.p2j.util.SecurityOps.*; import com.goldencode.p2j.xml.*; /** @@ -138,19 +141,19 @@ implements IHttpClientLibrary, ISupportLogging { @LegacySignature(type = Type.PROPERTY, name = "Logger") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) private object logger = TypeFactory.object(com.goldencode.p2j.oo.logging.IlogWriter.class); @LegacySignature(type = Type.PROPERTY, name = "LibraryName") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) private character libraryName = TypeFactory.character(); @LegacySignature(type = Type.PROPERTY, name = "LibraryVersion") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) private character libraryVersion = TypeFactory.character(); @LegacySignature(type = Type.PROPERTY, name = "Options") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) private object options = TypeFactory.object(com.goldencode.p2j.oo.net.http.ClientOptions.class); private object moSocketLib = TypeFactory.object(com.goldencode.p2j.oo.net.serverconnection.ClientSocket.class); @@ -292,7 +295,7 @@ * Get Library name. */ @LegacySignature(type = Type.GETTER, name = "LibraryName") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public character getLibraryName() { @@ -306,7 +309,7 @@ * Get Library version */ @LegacySignature(type = Type.GETTER, name = "LibraryVersion") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public character getLibraryVersion() { @@ -320,7 +323,7 @@ * Get Client options */ @LegacySignature(type = Type.GETTER, name = "Options") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public object getOptions() { @@ -334,12 +337,15 @@ * Get Client logger */ @LegacySignature(type = Type.GETTER, name = "Logger") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_PARTIAL) @Override public object getLogger() { return function(LegacySocketLibrary.class, this, "Logger", object.class, new Block((Body) () -> { + // TODO: use logger builder when available instead of void logger + if (!logger._isValid()) + logger.assign(ObjectOps.newInstance(VoidLogger.class)); returnNormal(logger); })); } @@ -352,7 +358,7 @@ { @LegacyParameter(name = "var", type = "OBJECT", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void setLogger(final object _var) { object var = TypeFactory.initInput(_var); @@ -408,7 +414,7 @@ @LegacyParameter(name = "poSocket", type = "OBJECT", qualified = "openedge.net.serverconnection.clientsocket", mode = "INPUT"), @LegacyParameter(name = "poSocketConnectionParams", type = "OBJECT", qualified = "openedge.net.serverconnection.clientsocketconnectionparameters", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_http_lib_sockets_LegacySocketLibrary_constructor__( final character _pcLibraryName, final character _pcLibraryVersion, @@ -427,7 +433,7 @@ @LegacyParameter(name = "poSocketConnectionParams", type = "OBJECT", qualified = "openedge.net.serverconnection.clientsocketconnectionparameters", mode = "INPUT"), @LegacyParameter(name = "poOptions", type = "OBJECT", qualified = "openedge.net.http.clientoptions", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __net_http_lib_sockets_LegacySocketLibrary_constructor__( final character _pcLibraryName, final character _pcLibraryVersion, @@ -590,15 +596,40 @@ port = uri.getPort().intValue(); } - character contentType = req.ref().getContentType(); java.net.URI _uri; try { - _uri = new URIBuilder(). - setScheme(scheme). - setHost(host). - setPort(port). - setPath(path).build(); + URIBuilder builder = new URIBuilder(). + setScheme(scheme). + setHost(host). + setPort(port). + setPath(path); + + String encoding = I18nOps.getJavaCharset(req.ref().getCharacterEncoding()); + + if (encoding != null && Charset.isSupported(encoding)) + builder.setCharset(Charset.forName(encoding)); + + object qryMap = uri.getQueryMap_1(); + + if (qryMap._isValid() && qryMap.ref().getSize().intValue() > 0) { + object iterator = qryMap.ref().getKeySet().ref().iterator(); + while (iterator.ref().hasNext().booleanValue()) + { + object key = iterator.ref().next_(); + object value = qryMap.ref().get(key); + + builder.addParameter(key.ref().toLegacyString().getValue(), + value.ref().toLegacyString().getValue()); + } + } + + String fragment = uri.getFragment().getValue(); + + if (!TextOps.isEmpty(fragment)) + builder.setFragment(fragment); + + _uri = builder.build(); } catch (URISyntaxException e) { @@ -693,6 +724,8 @@ } }). setSSLContext(sslContext). + setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build()). + build(); } === modified file 'src/com/goldencode/p2j/oo/web/IwebRequest.java' --- src/com/goldencode/p2j/oo/web/IwebRequest.java 2019-10-24 23:19:26 +0000 +++ src/com/goldencode/p2j/oo/web/IwebRequest.java 2021-01-28 07:49:19 +0000 @@ -8,6 +8,7 @@ ** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20190710 Added 'Headers[]' and 'ResolvedWebAppPath' property APIs . ** 003 CA 20191024 Added method support levels and updated the class support level. +** 004 ME 20210119 Removed non-existent methods. */ /* @@ -66,9 +67,7 @@ package com.goldencode.p2j.oo.web; import com.goldencode.p2j.util.*; -import com.goldencode.p2j.oo.lang.*; -import static com.goldencode.p2j.util.BlockManager.*; import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.InternalEntry.Type; @@ -81,32 +80,6 @@ public interface IwebRequest extends com.goldencode.p2j.oo.net.http.IhttpRequest { - @LegacySignature(type = Type.GETTER, name = "Headers", parameters = - { - @LegacyParameter(name = "idx", type = "INT64", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public object getHeaders(final int64 _idx); - - @LegacySignature(type = Type.SETTER, name = "Headers", parameters = - { - @LegacyParameter(name = "var", type = "OBJECT", mode = "INPUT"), - @LegacyParameter(name = "idx", type = "INT64", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public void setHeaders(final object _var, final int64 _idx); - - @LegacySignature(type = Type.LENGTH, name = "Headers") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public abstract integer lengthOfHeaders(); - - @LegacySignature(type = Type.RESIZE, name = "Headers", parameters = - { - @LegacyParameter(name = "size", type = "INT64", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public abstract void resizeHeaders(final int64 _size); - @LegacySignature(type = Type.GETTER, name = "ResolvedWebAppPath") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public character getResolvedWebAppPath(); === modified file 'src/com/goldencode/p2j/oo/web/RemoteWebRequest.java' --- src/com/goldencode/p2j/oo/web/RemoteWebRequest.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/oo/web/RemoteWebRequest.java 2021-01-30 11:34:48 +0000 @@ -8,6 +8,7 @@ ** 001 CA 20190924 First version. ** 002 CA 20191024 Added method support levels and updated the class support level. ** 003 CA 20200427 A more improved runtime. cookie/header and other support is still missing. +** 004 ME 20210128 Add errors for read-only, not implemented method/properties. */ /* @@ -65,6 +66,8 @@ package com.goldencode.p2j.oo.web; +import static com.goldencode.p2j.report.ReportConstants.CVT_LVL_FULL; +import static com.goldencode.p2j.report.ReportConstants.RT_LVL_FULL; import static com.goldencode.p2j.util.BlockManager.*; import java.io.*; @@ -216,15 +219,20 @@ } /** - * Set the HTTP method. This is a no-op. + * Set the HTTP method. This is read-only. * * @param method * the HTTP method. */ + @LegacySignature(type = Type.SETTER, name = "Method", parameters = + { + @LegacyParameter(name = "Method", type = "CHARACTER", mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public void setMethod(character method) { - // no-op + throwReadOnly("Method"); } /** @@ -239,15 +247,21 @@ } /** - * Set the HTTP URI. This is a no-op. + * Set the HTTP URI. This is read-only. * * @param uri * the HTTP URI. */ + @LegacySignature(type = Type.SETTER, name = "URI", parameters = + { + @LegacyParameter(name = "uri", type = "OBJECT", + qualified = "OpenEdge.Net.URI", mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public void setUri(object uri) { - // no-op + throwReadOnly("URI"); } /** @@ -262,15 +276,20 @@ } /** - * Set the character encoding. This is a no-op. + * Set the character encoding. This is read-only. * * @param _encoding * The character encoding. */ + @LegacySignature(type = Type.SETTER, name = "CharacterEncoding", parameters = + { + @LegacyParameter(name = "encoding", type = "CHARACTER", mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public void setCharacterEncoding(character _encoding) { - // no-op + throwReadOnly("CharacterEncoding"); } /** @@ -285,15 +304,20 @@ } /** - * Set the content length. This is a no-op. + * Set the content length. This is read-only. * * @param _var * The content length. */ + @LegacySignature(type = Type.SETTER, name = "ContentLength", parameters = + { + @LegacyParameter(name = "var", type = "INTEGER", mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public void setContentLength(integer _var) { - // no-op + throwReadOnly("ContentLength"); } /** @@ -309,15 +333,20 @@ } /** - * Set the content MD5. This is a no-op. + * Set the content MD5. This is not implemented. * * @param _var * The content MD5. */ + @LegacySignature(type = Type.SETTER, name = "ContentMD5", parameters = + { + @LegacyParameter(name = "var", type = "RAW", mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public void setContentMd5(raw _var) { - // no-op + throwNotImplementedProperty("ContentMD5"); } /** @@ -332,15 +361,20 @@ } /** - * Set the content type. This is a no-op. + * Set the content type. This is read-only. * * @param _var * The content type. */ + @LegacySignature(type = Type.SETTER, name = "ContentType", parameters = + { + @LegacyParameter(name = "var", type = "CHARACTER", mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public void setContentType(character _var) { - // no-op + throwReadOnly("ContentType"); } /** @@ -396,15 +430,21 @@ } /** - * Set the body entity. This is a no-op. + * Set the body entity. This is a read-only. * * @param _var * The body entity. */ + @LegacySignature(type = Type.SETTER, name = "Entity", parameters = + { + @LegacyParameter(name = "Entity", type = "OBJECT", + qualified = "Progress.Lang.Object", mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public void setEntity(object _var) { - // no-op + throwReadOnly("Entity"); } /** @@ -419,15 +459,20 @@ } /** - * Set the transfer encoding. This is a no-op. + * Set the transfer encoding. This is read-only. * * @param transferEncoding * The transfer encoding. */ + @LegacySignature(type = Type.SETTER, name = "TransferEncoding", parameters = + { + @LegacyParameter(name = "TransferEncoding", type = "CHARACTER", mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public void setTransferEncoding(character transferEncoding) { - // no-op + throwReadOnly("TransferEncoding"); } /** @@ -442,7 +487,7 @@ } /** - * Set the HTTP version. This is a no-op. + * Set the HTTP version. This is read-only. * * @param version * The HTTP version. @@ -450,16 +495,21 @@ @Override public void setVersion(character version) { - // no-op + throwReadOnly("Version"); } /** - * Clear the headers. This is a no-op. + * Clear the headers. This is not implemented. */ + @LegacySignature(type = Type.METHOD, name = "ClearHeaders") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public void clearHeaders() { - // no-op + internalProcedure(this, "ClearHeaders", new Block((Body) () -> + { + throwNotImplementedMethod("ClearHeaders"); + })); } /** @@ -533,89 +583,68 @@ } /** - * Remove the specified header. This is a no-op. + * Remove the specified header. This is not implemented. * * @param _pcName * The header name. */ + @LegacySignature(type = Type.METHOD, name = "RemoveHeader", parameters = + { + @LegacyParameter(name = "pcName", type = "CHARACTER", mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public void removeHeader(character _pcName) { - // no-op + internalProcedure(this, "RemoveHeader", new Block((Body) () -> + { + throwNotImplementedMethod("RemoveHeader"); + })); } /** - * Set the specified header. This is a no-op. + * Set the specified header. This is not implemented. * * @param _poHeader * The header instance. */ + @LegacySignature(type = Type.METHOD, name = "SetHeader", parameters = + { + @LegacyParameter(name = "poHeader", type = "OBJECT", + qualified = "OpenEdge.Net.HTTP.HttpHeader", mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public void setHeader(object _poHeader) { - // no-op - } - - /** - * Get the header on the specified position. - * - * @param _idx - * The header index. - * - * @return The header instance. - */ - @Override - public object getHeaders(int64 _idx) - { - UnimplementedFeature.missing("RemoteWebRequest.getHeaders"); - return new object(); - } - - /** - * Set the specified header on the specified location. This is a no-op. - * - * @param _var - * The header instance. - * @param _idx - * The header location. - */ - @Override - public void setHeaders(object _var, int64 _idx) - { - // no-op - } - - /** - * Calculate the number of headers. - * - * @return See above. - */ - @Override - public integer lengthOfHeaders() - { - Enumeration hnames = request.getHeaderNames(); - int size = 0; - while (hnames.hasMoreElements()) - { - String header = hnames.nextElement(); - size = size + 1; - } - - return new integer(size); - } - - /** - * Resize the headers. This is a no-op. - * - * @param _size - * The header size. - */ - @Override - public void resizeHeaders(int64 _size) - { - // no-op - } - + internalProcedure(this, "SetHeader", new Block((Body) () -> + { + throwNotImplementedMethod("SetHeader"); + })); + } + + + /** + * Set the specified header. This is not implemented. + * + * @param _pcName + * The header name. + * @param _pcValue + * The header value. + */ + @LegacySignature(type = Type.METHOD, name = "SetHeader", parameters = + { + @LegacyParameter(name = "poHeader", type = "CHARACTER", mode = "INPUT") + }, qualified = "OpenEdge.Net.HTTP.HttpHeader") + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public object setHeader(character _pcName, character _pcValue) + { + return function(this, "SetHeader", object.class, new Block((Body) () -> + { + throwNotImplementedMethod("SetHeader"); + })); + } + /** * Resolve the web app path. * @@ -1013,7 +1042,7 @@ } /** - * Remove the specified cookie. This is a no-op. + * Remove the specified cookie. This is not implemented. * * @param _pcName * The cookie name. @@ -1021,7 +1050,10 @@ @Override public void removeCookie(character _pcName) { - // no-op + internalProcedure(this, "RemoveCookie", new Block((Body) () -> + { + throwNotImplementedMethod("RemoveCookie"); + })); } /** @@ -1065,10 +1097,30 @@ } + @LegacySignature(type = Type.METHOD, name = "SetHeader", parameters = + { + @LegacyParameter(name = "poHeader", type = "OBJECT", + qualified = "OpenEdge.Net.HTTP.HttpHeader", extent = -1, mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public void setHeaders(object[] _poHeader) { - // TODO Auto-generated method stub - + throwNotImplementedMethod("SetHeaders"); + } + + private void throwReadOnly (String name) + { + undoThrow(AppError.newInstance(TextOps.substitute("OpenEdge.Web.WebRequest.&1 property is read-only", name), new integer())); + } + + private void throwNotImplementedMethod (String name) + { + undoThrow(AppError.newInstance(TextOps.substitute("OpenEdge.Web.WebRequest.&1 method is not implemented", name), new integer())); + } + + private void throwNotImplementedProperty (String name) + { + undoThrow(AppError.newInstance(TextOps.substitute("OpenEdge.Web.WebRequest.&1 property is not implemented", name), new integer())); } } === modified file 'src/com/goldencode/p2j/oo/web/WebResponse.java' --- src/com/goldencode/p2j/oo/web/WebResponse.java 2019-10-24 23:19:26 +0000 +++ src/com/goldencode/p2j/oo/web/WebResponse.java 2021-01-25 07:38:12 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 CA 20190526 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20191024 Added method support levels and updated the class support level. +** 003 ME 20210125 Added missing ctor, implement as per OE12.2. */ /* @@ -65,20 +66,22 @@ package com.goldencode.p2j.oo.web; import com.goldencode.p2j.util.*; -import com.goldencode.p2j.oo.lang.*; +import com.goldencode.p2j.util.BlockManager.Action; +import com.goldencode.p2j.util.BlockManager.Condition; +import com.goldencode.p2j.oo.net.http.HttpHeaderBuilder; +import com.goldencode.p2j.oo.net.http.StatusCodeEnum; +import com.goldencode.p2j.oo.net.http.StatusCodeHelper; import static com.goldencode.p2j.util.BlockManager.*; import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.InternalEntry.Type; -import javax.servlet.http.*; - /** * Business logic (converted to Java from the 4GL source code * in OpenEdge/Web/WebResponse.cls). */ @LegacyResource(resource = "OpenEdge.Web.WebResponse") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_PARTIAL) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class WebResponse extends com.goldencode.p2j.oo.net.http.HttpResponse { @@ -86,8 +89,7 @@ { externalProcedure(WebResponse.this, new Block((Body) () -> { - { - } + onBlockLevel(Condition.ERROR, Action.THROW); })); } @@ -97,16 +99,53 @@ { internalProcedure(this, "__web_WebResponse_constructor__", new Block((Body) () -> { + __web_WebResponse_constructor__(new integer(200)); + })); + } + + @LegacySignature(type = Type.CONSTRUCTOR, parameters = + { + @LegacyParameter(name = "pStatusCode", type = "OBJECT", mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void __web_WebResponse_constructor__(final object _pStatusCode) + { + object pStatusCode = TypeFactory.initInput(_pStatusCode); + + internalProcedure(this, "__web_WebResponse_constructor__", new Block((Body) () -> + { + __web_WebResponse_constructor__(new integer(pStatusCode)); + })); + } + + @LegacySignature(type = Type.CONSTRUCTOR, parameters = + { + @LegacyParameter(name = "pStatusCode", type = "INTEGER", mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void __web_WebResponse_constructor__(integer _pStatusCode) + { + integer pStatusCode = TypeFactory.initInput(_pStatusCode); + + internalProcedure(this, "__web_WebResponse_constructor__", new Block((Body) () -> + { __net_http_HttpResponse_constructor__(); + + // headers/cookies collections needs to be initialized + initialize(); + + setStatusCode(pStatusCode); + setStatusReason(StatusCodeHelper.getMessage(pStatusCode)); + setVersion(new character("HTTP/1.1")); })); } - + @LegacySignature(type = Type.METHOD, name = "SetHeader", parameters = { @LegacyParameter(name = "p1", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "p2", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_PARTIAL) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void setHeader(final character _p1, final character _p2) { character p1 = TypeFactory.initInput(_p1); @@ -114,25 +153,8 @@ internalProcedure(this, "SetHeader", new Block((Body) () -> { - // TODO: validate these - HttpServletResponse response = WebHandler.getHttpResponse(); - if (response != null) - { - String name = p1.toStringMessage(); - if (name.isEmpty()) - { - // DO NOT OUTPUT EMPTY HEADER NAMES! This will abend clients like Postman or SoapUI - System.err.println("Empty header name!"); - } - else - { - response.setHeader(name, p2.toStringMessage()); - } - } - else - { - // TODO: what to do? - } + // let the http header builder handle everything... + setHeader(HttpHeaderBuilder.build(p1).ref().value(p2).ref().getHeader()); })); } } === modified file 'src/com/goldencode/p2j/persist/BufferImpl.java' --- src/com/goldencode/p2j/persist/BufferImpl.java 2021-01-29 00:53:41 +0000 +++ src/com/goldencode/p2j/persist/BufferImpl.java 2021-01-31 10:14:52 +0000 @@ -2084,7 +2084,7 @@ if (hibernateName == null) { String msg = "BUFFER-FIELD " + fieldName + " was not found in buffer " + legacyTableName; - ErrorManager.recordOrShowError(7351, msg, false, false, false); + ErrorManager.recordOrThrowError(7351, msg, false, false); // return unknown handle return new handle(); === modified file 'src/com/goldencode/p2j/persist/serial/JsonExport.java' --- src/com/goldencode/p2j/persist/serial/JsonExport.java 2021-01-27 01:54:24 +0000 +++ src/com/goldencode/p2j/persist/serial/JsonExport.java 2021-01-31 10:14:52 +0000 @@ -17,6 +17,7 @@ ** 006 CA 20200914 Added blob, raw, rowid and handle support. ** 007 CA 20200927 Use IdentityHashMap instead of plain map when the key is a Class. ** 008 OM 20201120 Improved compatibility with P4GL. +** 009 ME 20210130 Added serializeTempTable method into JsonArray. */ /* @@ -578,6 +579,46 @@ } /** + * Actual implementation of a table serialization into a JsonArray (only rows). + * + * @param json + * The target of the deserialized json data. + * @param buffer + * A buffer of the temp-table to be serialized. + * @param noInit + * Skip the initial values. + + * @throws IOException + * If exceptions occur during the serialization. + */ + public boolean serializeTempTable(JsonStructureCallback json, + TemporaryBuffer buffer, + boolean noInit) + throws IOException + { + TempTableSchema schema = new TempTableSchema(buffer); + TempTable tempTable = (TempTable) buffer.tableHandle().get(); + String serializeName = tempTable.getSerializeName().toJavaType(); + String tableName = serializeName != null && !serializeName.isEmpty() + ? serializeName + : schema.getTableName(); + + buffer.readAllRows( + (dmo) -> writeRecord(json, + buffer, + dmo, + schema, + tableName, + false, + false, + false, + false, + noInit)); + + return true; + } + + /** * Serialize a single record to the JSON output. * * @param json === modified file 'src/com/goldencode/p2j/util/ArrayAssigner.java' --- src/com/goldencode/p2j/util/ArrayAssigner.java 2020-10-09 15:23:21 +0000 +++ src/com/goldencode/p2j/util/ArrayAssigner.java 2021-01-29 07:59:08 +0000 @@ -53,6 +53,8 @@ ** 024 CA 20190812 Fixed 'isObject' - check if the class is object or a subclass. ** 025 CA 20201003 Replaced Guava identity HashSet with Collections.newSetFromMap(IdentityHashMap). ** ME 20201009 Add new 'assignMulti' method with Object input to work with Class.invoke. +** 20201019 Save the object type reference on resize back to indeterminate array. +** 20210128 Register as dynamic when resize back to indeterminate array. */ /* @@ -1121,9 +1123,24 @@ Class cls = (Class) array.getClass().getComponentType(); T[] copy = (T[]) Array.newInstance(cls, (int) size); + if (size == 0) + registerDynamicArray(copy); + boolean isObject = object.class.isAssignableFrom(array.getClass().getComponentType()); // if this object array was resized, is no longer needed to keep the type Class objType = isObject ? wa.dynamicArrayType.remove(array) : null; + + if (isObject && size == 0) { + // reset back to indeterminate size, save the type + if (objType == null && array.length > 0) + { + objType = (Class) ((object) array[0]).type(); + } + + if (objType != null) + wa.dynamicArrayType.put((object[]) copy, objType); + } + for (int i = 0; i < copy.length; i++) { if (isObject) === modified file 'src/com/goldencode/p2j/util/BaseDataType.java' --- src/com/goldencode/p2j/util/BaseDataType.java 2020-10-09 17:55:08 +0000 +++ src/com/goldencode/p2j/util/BaseDataType.java 2021-01-31 10:14:52 +0000 @@ -115,6 +115,8 @@ import java.lang.reflect.*; import java.util.*; +import com.goldencode.p2j.persist.FieldReference; + /** * An abstract class that implements a Progress 4GL compatible data type * which has common logical operator processing. Meant to be the parent @@ -671,6 +673,10 @@ { assign(new logical((Boolean) value)); } + else if (value instanceof FieldReference) + { + assign(((FieldReference) value).get()); + } else { UnimplementedFeature.missing("BDT.assign(" + value.getClass() + ")"); === modified file 'src/com/goldencode/p2j/util/BinaryData.java' --- src/com/goldencode/p2j/util/BinaryData.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/util/BinaryData.java 2020-10-19 06:36:56 +0000 @@ -3578,7 +3578,7 @@ * Generate the standard error message in the case where an invalid * index position (< 1) is used. */ - private void genIndexError() + public static void genIndexError() throws ErrorConditionException { String err = "Byte position for PUT-BYTE, GET-BYTE and other" + === modified file 'src/com/goldencode/p2j/util/Call.java' --- src/com/goldencode/p2j/util/Call.java 2020-10-09 15:23:21 +0000 +++ src/com/goldencode/p2j/util/Call.java 2021-01-30 11:45:36 +0000 @@ -86,6 +86,7 @@ import com.goldencode.p2j.convert.*; import com.goldencode.p2j.library.*; +import com.goldencode.p2j.oo.lang._BaseObject_; import com.goldencode.p2j.persist.*; import com.goldencode.p2j.uast.*; import com.goldencode.p2j.ui.*; @@ -132,7 +133,7 @@ /** A cache of data types. */ private static final Set DATA_TYPES = new HashSet<>(); - private static Pattern dataTypePattern = Pattern.compile("^(CLASS\\s+)?([\\w|\\.]+)(\\s+EXTENT)?$"); + private static Pattern dataTypePattern = Pattern.compile("^(CLASS\\s+)?([\\w|\\.]+)(\\s+EXTENT)?$", Pattern.CASE_INSENSITIVE); static { @@ -1746,7 +1747,7 @@ return new logical(false); } - CallParameter param = createParameter(dataType.getValue(), cmode, value, library); + CallParameter param = createParameter(dataType.getValue(), cmode, value, library != null, false); if (param == null) { @@ -2112,6 +2113,11 @@ *

* If validation fails (invalid data type, mode or value combinations), then a null * value will be returned. + * + * When calling external dynamic/shared library routine parameter data type is validated for + * supported external data types. + * + * SetParameter method in ParametersList does an extra validation on input value against data type. * * @param dataType * The data type to be used. @@ -2119,11 +2125,14 @@ * The parameter's mode. * @param value * The parameter's value. - * + * @param library + * Flag set to true if a dynamic/shared library routine is invoked. + * @param validateType + * Optional data type validation * @return A new {@link CallParameter instance} with the parameter configuration. */ public static CallParameter createParameter(String dataType, CallMode mode, Object value, - String library) + boolean library, boolean validateType) { boolean isVar = (value instanceof BaseDataTypeVariable); if (isVar) @@ -2141,17 +2150,9 @@ isExtent = dataTypeMatch.group(3) != null; } - if (!isClass) { - dataType = ProgressAst._keyword(dataType); - if ("log".equalsIgnoreCase(dataType)) - { - // we have a conflict with 'log' function - dataType = "logical"; - } - } + dataType = resolveDataType(dataType); - Class cls = null; - if (library != null) + if (library) { if (!validDllType(dataType)) { @@ -2161,56 +2162,42 @@ "SET-PARAMETER datatype " + dataType + " is not " + "supported for WINDOWS DLL or UNIX library CALL object", false); - return null; } } else { + // dataset and table parameter + if (value instanceof DataSetParameter || value instanceof TableParameter + || "DATASET".equalsIgnoreCase(dataType) || "TABLE".equalsIgnoreCase(dataType)) + { + if ((value instanceof DataSetParameter && !"DATASET".equalsIgnoreCase(dataType)) + || (value instanceof TableParameter && !"TABLE".equalsIgnoreCase(dataType)) + || ("DATASET".equalsIgnoreCase(dataType) + && !(value instanceof DataSetParameter)) + || ("TABLE".equalsIgnoreCase(dataType) && !(value instanceof TableParameter))) + { + ErrorManager.recordOrThrowError(15563, + "If either the 2nd or 4th parameters to SetParameter are TABLE " + + "or DATASET types, then they both must be.", + false); + } + + return new CallParameter(dataType, mode, value); + } + + Class cls = !isClass && dataType != null + && DATA_TYPES.contains(dataType.toUpperCase()) + ? BaseDataType.fromTypeName(dataType) + : ObjectOps.resolveClass(dataType); + Runnable invalidType = () -> { ErrorManager.recordOrThrowError(10059, "Unable to convert SET-PARAMETER value to datatype passed", false); }; - if (dataType == null || !DATA_TYPES.contains(dataType.toUpperCase())) - { - invalidType.run(); - return null; - } - - if ((value instanceof DataSetParameter && !"DATASET".equalsIgnoreCase(dataType)) - || (value instanceof TableParameter && !"TABLE".equalsIgnoreCase(dataType)) - || ("DATASET".equalsIgnoreCase(dataType) - && !(value instanceof DataSetParameter)) - || ("TABLE".equalsIgnoreCase(dataType) && !(value instanceof TableParameter))) - { - ErrorManager.recordOrThrowError(15563, - "If either the 2nd or 4th parameters to SetParameter are TABLE " - + "or DATASET types, then they both must be.", - false); - return null; - } - else if ((value instanceof memptr) && !"MEMPTR".equalsIgnoreCase(dataType) - || ("MEMPTR".equalsIgnoreCase(dataType) && !(value instanceof memptr))) - { - ErrorManager.recordOrThrowError(10058, - "MEMPTR parameters may not be converted to any other " - + "type in dynamic invoke or SetParameter", - false); - return null; - } - else if (("TABLE-HANDLE".equalsIgnoreCase(dataType) - || "DATASET-HANDLE".equalsIgnoreCase(dataType)) && !(value instanceof handle)) - { - invalidType.run(); - return null; - } - - cls = BaseDataType.fromTypeName(dataType); - if (cls == null) { invalidType.run(); - return null; } if (value != null) @@ -2231,11 +2218,25 @@ valueCls = valueCls.getComponentType(); } + if ((valueCls.isAssignableFrom(memptr.class)) && !"MEMPTR".equalsIgnoreCase(dataType) + || ("MEMPTR".equalsIgnoreCase(dataType) && !(valueCls.isAssignableFrom(memptr.class)))) + { + ErrorManager.recordOrThrowError(10058, + "MEMPTR parameters may not be converted to any other " + + "type in dynamic invoke or SetParameter", + false); + } + else if (("TABLE-HANDLE".equalsIgnoreCase(dataType) + || "DATASET-HANDLE".equalsIgnoreCase(dataType)) && !(valueCls.isAssignableFrom(handle.class))) + { + invalidType.run(); + } + if (!isValExtent) { // run-time data type conversion seems to be attempted first even if data types does not match unless is extent try { - BaseDataType inst = BaseDataType.generateUnknown(cls); + BaseDataType inst = _BaseObject_.class.isAssignableFrom(cls) ? TypeFactory.object((Class) cls) : BaseDataType.generateUnknown(cls); inst.assign(value); } catch (ErrorConditionException ece) @@ -2255,13 +2256,23 @@ // date->datetime->datetimetz hierarchy works // decimal accepts both integer/int64 - if (!valueCls.isAssignableFrom(cls) - && (!cls.equals(decimal.class) || !int64.class.isAssignableFrom(valueCls))) + if (validateType) { - ErrorManager.recordOrThrowError(15315, - "SetParameter found incompatible data types used in dynamic parameter", - false); - return null; + if (!valueCls.isAssignableFrom(cls) + && (!cls.equals(decimal.class) || !int64.class.isAssignableFrom(valueCls))) + { + ErrorManager.recordOrThrowError(15315, + "SetParameter found incompatible data types used in dynamic parameter", + false); + } + + if (isExtent && !isValExtent) + { + ErrorManager.recordOrThrowError(15308, + "SetParameter requires that the EXTENT keyword must FOLLOW the datatype when the value is an array, but not when the value is a scalar", + false); + } + } } @@ -2272,7 +2283,7 @@ return new ExtentCallParameter(dataType, mode, value); } - CallParameter cparam = library != null ? new NativeCallParameter(dataType, mode, value) + CallParameter cparam = library ? new NativeCallParameter(dataType, mode, value) : new CallParameter(dataType, mode, value); return cparam; @@ -2700,6 +2711,22 @@ return cfg; } + private static String resolveDataType(String dataType) + { + String primitiveType = ProgressAst._keyword(dataType); + + if (primitiveType != null && (DATA_TYPES.contains(primitiveType.toUpperCase()) + || validDllType(primitiveType))) + { + return "log".equalsIgnoreCase(primitiveType) ? "logical" : primitiveType; + } + + // if not a primitive data type check a valid OO class + Class<_BaseObject_> cls = ObjectOps.resolveClass(dataType); + + return cls != null ? dataType : null; + } + /** * Given a decimal value, convert it to a byte representation; this representation is assumed * as an 'in memory representation' of the value, usable for converting to another data type, === modified file 'src/com/goldencode/p2j/util/ControlFlowOps.java' --- src/com/goldencode/p2j/util/ControlFlowOps.java 2021-01-26 23:48:21 +0000 +++ src/com/goldencode/p2j/util/ControlFlowOps.java 2021-01-31 10:14:52 +0000 @@ -5258,12 +5258,16 @@ if (candidateType == object.class && sigType == object.class) { slegacy = ((object) arg).type(); - clegacy = ObjectOps.resolveClass(param.getQualified()); + clegacy = param.getQualified() == null ? _BaseObject_.class : ObjectOps.resolveClass(param.getQualified()); // qualified parameter name might be a super class/interface if (clegacy == null) { clegacy = ObjectOps.getAssignableClass(param.getQualified(), (Class) slegacy); } + + // if not qualified defaults to P.L.O (interface) + if (clegacy == null || clegacy.equals(BaseObject.class)) + clegacy = _BaseObject_.class; } else if (candidateType == jobject.class && sigType == jobject.class) { try { === modified file 'src/com/goldencode/p2j/util/DeferredProgramWrapper.java' --- src/com/goldencode/p2j/util/DeferredProgramWrapper.java 2020-09-07 16:23:31 +0000 +++ src/com/goldencode/p2j/util/DeferredProgramWrapper.java 2020-12-03 09:05:07 +0000 @@ -8,6 +8,7 @@ ** 001 CA 20190628 Created initial version. ** 002 AIL 20200622 Made use of the new procedure delete signature. ** Changed the behavior of multiple deletes when there is a server instance. +** 003 ME 20201203 Internal entries is unknown for 'proxy' procedures. */ /* ** This program is free software: you can redistribute it and/or modify @@ -104,7 +105,7 @@ */ public character internalEntries() { - return new character(""); + return new character(); } /** === modified file 'src/com/goldencode/p2j/util/ErrorManager.java' --- src/com/goldencode/p2j/util/ErrorManager.java 2021-01-27 01:54:24 +0000 +++ src/com/goldencode/p2j/util/ErrorManager.java 2021-01-31 10:14:52 +0000 @@ -190,11 +190,14 @@ ** was treating an error code as a key code. ** GES 20200820 Safety code in case ErrorHelper is requested on the client side. ** GES 20200821 Added ErrorHelper.isSuppressWarnings(). +** ME 20201014 Do not append error number if zero, there are system errors thrown with number set to zero. ** OM 20201020 Renamed warning to errorsAsWarnings and added accessors in ErrorHelper. ** Added some missing error messages. ** OM 20201120 Changed method name to match no-bean prefixes buffer convention. ** 20201125 displayError is no-op in silent mode. ** OM 20201203 Fixed handling of READ/ONLY attributes. +** ME 20210128 Add helper method for 'invalid parameter' error and push all messages from an +** OO error up the stack for silent execution. */ /* @@ -1771,9 +1774,13 @@ // be called quite often in normal control flow, and String.format is expensive StringBuilder buf = (prefix ? new StringBuilder("** ") : new StringBuilder()); buf.append(text); - buf.append(addDot ? ". (" : " ("); - buf.append(num); - buf.append(')'); + + // SysError with error number 0 does not add this + if (num > 0) { + buf.append(addDot ? ". (" : " ("); + buf.append(num); + buf.append(')'); + } return buf.toString(); } @@ -2744,7 +2751,7 @@ case 11967: msg = "CLEAR may not be used on a static dataset"; break; case 11968: msg = "First argument to DATASET:CREATE-LIKE must be a valid dataset handle or name\""; break; // yes, the double quote is part of error message case 11969: msg = "Unable to CLEAR target CREATE-LIKE dataset"; break; -case 11971: msg = "Cannot delete a relation of a dataset"; break; + case 11971: msg = "Cannot delete a relation of a dataset"; break; case 11973: msg = "You may not change the buffers for a static data-source"; break; case 11974: msg = "The first argument to ADD-SOURCE-BUFFER must be a valid buffer handle"; break; case 11975: msg = "ADD-SOURCE-BUFFER key name %1 must be a field in buffer %2"; break; @@ -3229,10 +3236,17 @@ if (!(err instanceof AppError) || !((AppError) err).isFromReturn()) { ProError proErr = (ProError) err; - int errnum = proErr.getMessageNum(new integer(1)).intValue(); - String errmsg = proErr.getMessage(new integer(1)).toStringMessage(); - wa.pendingErrorStatus.errorList.add(new ErrorEntry(errnum, errmsg)); - addRaisedConditionWorker(wa, new int[] { errnum }); + int numErr = err.getNumMessages().intValue(); + int[] errnums = new int[numErr]; + String[] errmsgs = new String[numErr]; + + for (int i = 0; i < numErr; i++) + { + errnums[i] = proErr.getMessageNum(new integer(i + 1)).intValue(); + errmsgs[i] = proErr.getMessage(new integer(i + 1)).toStringMessage(); + wa.pendingErrorStatus.errorList.add(new ErrorEntry(errnums[i], errmsgs[i])); + } + addRaisedConditionWorker(wa, errnums); } } catch (ErrorConditionException err) @@ -3421,6 +3435,15 @@ } } + public static String getInvalidParameterError(String type, _BaseObject_ instance, String method, String errMsg) + { + return String.format("Invalid %s parameter to %s:%s( ). %s", + type, + instance.getLegacyClass().ref().getTypeName().getValue(), + method, + errMsg); + } + /** * Helper to expose error state in a way that avoids context local lookups. */ === modified file 'src/com/goldencode/p2j/util/ObjectOps.java' --- src/com/goldencode/p2j/util/ObjectOps.java 2020-10-14 07:40:03 +0000 +++ src/com/goldencode/p2j/util/ObjectOps.java 2021-01-31 10:14:52 +0000 @@ -42,6 +42,8 @@ ** CA 20201014 Reverted ME/20201009 - 'invoke' will return BDT, and the fix will either emit a ** 'invokeExtent' for calls where it is known for the lvalue to be an extent, or we add ** BDT(Object) constructors for all sub-classes. +** ME 20201127 Throw error instead of showing it if cast fails. +** ME 20210128 Added cast/dynamic cast for object arrays. */ /* @@ -105,6 +107,8 @@ import java.lang.reflect.*; import java.util.*; +import org.reflections.Reflections; + /** * Defines APIs to manage 4GL-style objects (instantiation, deletion, cast, etc). */ @@ -131,6 +135,20 @@ } }; + + + static + { + // register all classes from 'oo sdk' implementation + Reflections reflections = new Reflections("com.goldencode.p2j.oo"); + Set> legacyClasses = + reflections.getSubTypesOf(_BaseObject_.class); + + for (Class cls : legacyClasses) { + registerClass(cls, false); + } + } + /** * Register all specified object variables (scalar or extent) for scope notification. The * notification will only process for top-level scopes. When their defining top-level block @@ -1071,7 +1089,7 @@ String t2 = getLegacyName(cls); // at least for enums this is a warning, the error-status:error is false - ErrorManager.recordOrShowError(12869, "Invalid cast from " + t1 + " " + t2, false, true, false); + ErrorManager.recordOrThrowError(12869, "Invalid cast from " + t1 + " " + t2, false, false); // unknown object is returned return new object(); @@ -1079,6 +1097,28 @@ return new object((T) o.ref); } + + /** + * Cast this object array to the specified type. + * + * @param o + * The object array instance. + * @param cls + * The type to check. + * + * @return A new {@link object} array instance, if the cast is possible. + */ + public static object[] cast(object[] o, Class cls) + { + object[] objArr = TypeFactory.objectExtent(o.length, cls); + + for (int i = 0; i < objArr.length; i++) + { + objArr[i].assign(cast(o[i], cls)); + } + + return objArr; + } /** * Find and return the specified enum. @@ -1235,11 +1275,10 @@ if (cls == null) { - ErrorManager.recordOrShowError(12900, + ErrorManager.recordOrThrowError(12900, "CAST to '" + legacyClsName + "' not allowed. " + - "CAST target must be a user-defined type", + "CAST target must be a user-defined type", false, - true, false); return new object<>(); } @@ -1261,20 +1300,91 @@ { if (legacyClsName.isUnknown() || legacyClsName.toStringMessage().isEmpty()) { - ErrorManager.recordOrShowError(12900, + ErrorManager.recordOrThrowError(12900, + "CAST to 'UNKNOWN' not allowed. " + + "CAST target must be a user-defined type", + false, + false); + + return new object<>(); + } + + return dynamicCast(o, legacyClsName.toStringMessage()); + } + + /** + * Cast this object array to the specified type, resolved dynamically. + * + * @param o + * The object array instance. + * @param legacyClsName + * The legacy class name. This may be qualified or unqualified. + * + * @return A new {@link object} array instance, if the cast is possible. + */ + public static object[] dynamicCast(object[] o, character legacyClsName) + { + if (legacyClsName.isUnknown() || legacyClsName.toStringMessage().isEmpty()) + { + ErrorManager.recordOrThrowError(12900, "CAST to 'UNKNOWN' not allowed. " + "CAST target must be a user-defined type", false, - true, false); - - return new object<>(); } return dynamicCast(o, legacyClsName.toStringMessage()); } /** + * Cast this object array to the specified type, resolved dynamically. + * + * @param o + * The object array instance. + * @param legacyClsName + * The legacy class name. This may be qualified or unqualified. + * + * @return A new {@link object} array instance, if the cast is possible. + */ + public static object[] dynamicCast(object[] o, String legacyClsName) + { + Class cls = resolveClass(legacyClsName); + + if (cls == null) + { + ErrorManager.recordOrThrowError(12900, + "CAST to '" + legacyClsName + "' not allowed. " + + "CAST target must be a user-defined type", + false, + false); + } + + object<_BaseObject_>[] objArr = TypeFactory.objectExtent(o.length, _BaseObject_.class); + + int numErr = 0; + int[] errNums = new int[o.length]; + String[] errMsgs = new String[o.length]; + + for (int i = 0; i < objArr.length; i++) + { + final int idx = i; + + if (ErrorManager + .silent(() -> objArr[idx].assign(cast(o[idx], cls)))) + { + errNums[numErr] = ErrorManager.getErrorNumber(1).intValue(); + errMsgs[numErr] = ErrorManager.getErrorText(1).getValue(); + numErr++; + } + } + + if (numErr > 0) + ErrorManager.recordOrThrowError(Arrays.copyOf(errNums, numErr), Arrays.copyOf(errMsgs, numErr), false, false); + + return objArr; + } + + /** * Get the THIS-OBJECT system reference. * * @return See above. === modified file 'src/com/goldencode/p2j/util/Text.java' --- src/com/goldencode/p2j/util/Text.java 2020-10-01 19:21:08 +0000 +++ src/com/goldencode/p2j/util/Text.java 2020-10-23 13:23:04 +0000 @@ -2145,6 +2145,10 @@ */ public void assign(BaseDataType value) { + if (value instanceof raw || value instanceof memptr || value instanceof blob) + { + incompatibleTypesOnConversion(); + } if (value == null || value.isUnknown()) { setUnknown(); @@ -2161,7 +2165,7 @@ { assign((jobject) value); } - else if (value instanceof raw || value instanceof rowid || value instanceof memptr) + else if (value instanceof rowid) { incompatibleTypesOnConversion(); } === modified file 'src/com/goldencode/p2j/util/TextOps.java' --- src/com/goldencode/p2j/util/TextOps.java 2020-12-02 20:44:27 +0000 +++ src/com/goldencode/p2j/util/TextOps.java 2021-01-31 10:14:52 +0000 @@ -35,8 +35,10 @@ ** EVL 20200922 Rework for frequently used string operations. Reverted from 11575 to 11573 back due to ** slowing down. ** ME 20201009 Added helper method to check if text is empty (unknown or contains only spaces). +** ME 20201127 Use resource id for objects in substitute. +** OM 20201202 Fixed support for substitution of Java Boolean values. ** VVT 20210106 splitInt(): typo in javadoc fixed. -** OM 20201202 Fixed support for substitution of Java Boolean values. +** ME 20210128 Avoid using java's trim to check if string is empty, 4GL only consider spaces to be empty (not tab, cr, lf). */ /* @@ -5855,7 +5857,8 @@ * @return True if the string is null, empty or contains only spaces. */ public static boolean isEmpty (String value) { - return value == null || value.trim().isEmpty(); + // only real spaces are considered (not tab, cr, lf) + return value == null || value.replaceAll(" ", "").isEmpty(); } /** @@ -6449,6 +6452,11 @@ character ch = (character) obj; sb.append(ch.isUnknown() ? "?" : ch.getValue()); } + else if (obj instanceof object) + { + object o = (object) obj; + sb.append(object.resourceId(o)); + } else if (obj instanceof BaseDataType) { BaseDataType bdt = (BaseDataType) obj; === modified file 'src/com/goldencode/p2j/util/TypeFactory.java' --- src/com/goldencode/p2j/util/TypeFactory.java 2019-10-02 15:39:05 +0000 +++ src/com/goldencode/p2j/util/TypeFactory.java 2021-01-15 07:15:17 +0000 @@ -19,6 +19,7 @@ ** 006 OM 20190626 Added chained-attribute expression error in handle. ** 007 CA 20190719 INPUT parameters must do reference counting always. ** 008 CA 20190927 Added support for direct Java access from 4GL code. +** 008 ME 20201125 Register newly created object array with indeterminate extent as dynamic. */ /* @@ -650,10 +651,7 @@ */ public static object[] objectExtent(Class cls) { - object[] res = new object[0]; // unchecked warning - ArrayAssigner.setObjectType(res, cls); - - return res; + return objectExtent(0, cls); } /** @@ -671,6 +669,14 @@ { object[] res = new object[extent]; // unchecked warning + if (extent == 0) + { + // register indeterminate extent array as dynamic else a latter assign will fail + ArrayAssigner.registerDynamicArray(res); + + ArrayAssigner.setObjectType(res, cls); + } + for (int i = 0; i < extent; i++) { res[i] = new ObjectVar(cls); === modified file 'src/com/goldencode/p2j/util/Utils.java' --- src/com/goldencode/p2j/util/Utils.java 2020-10-11 16:07:42 +0000 +++ src/com/goldencode/p2j/util/Utils.java 2021-01-31 10:14:52 +0000 @@ -152,6 +152,7 @@ ** CA 20201003 Use an identity HashSet where possible. ** CA 20201011 Added intersect() and containsAll() for RoaringBitmap (fast-access bitmap used ** instead of integer sets). +** ME 20210121 Fix longToBytesLE to use little end order. */ /* @@ -4659,14 +4660,14 @@ { return new byte[] { - (byte) (l >> 56), + (byte) l, + (byte) (l >> 8), + (byte) (l >> 16), + (byte) (l >> 24), + (byte) (l >> 32), + (byte) (l >> 40), (byte) (l >> 48), - (byte) (l >> 40), - (byte) (l >> 32), - (byte) (l >> 24), - (byte) (l >> 16), - (byte) (l >> 8), - (byte) l + (byte) (l >> 56) }; } === modified file 'src/com/goldencode/p2j/util/date.java' --- src/com/goldencode/p2j/util/date.java 2020-10-08 21:34:55 +0000 +++ src/com/goldencode/p2j/util/date.java 2021-01-14 09:33:28 +0000 @@ -195,6 +195,7 @@ ** 086 OM 20200616 ParsedDateFormat API changes. ** 087 HC 20200806 Added OCX_EPOCH_OFFSET. ** 088 IAS 20201007 Added Type enum +** 089 ME 20210114 Throw invalid data type conversion when assigned longchar/clob/blob even if unknown. */ /* @@ -2284,10 +2285,21 @@ { long oldJulian = julian; - if (value == null || value.isUnknown()) + if (value == null) { setUnknown(); } + else if (value.isUnknown()) + { + if (value instanceof longchar || value instanceof clob || value instanceof blob) + { + incompatibleTypesOnConversion(); + } + else + { + setUnknown(); + } + } else if (value instanceof date) { // this is the common path, also handles datetime and datetimetz === modified file 'src/com/goldencode/p2j/util/handle.java' --- src/com/goldencode/p2j/util/handle.java 2021-01-13 21:04:41 +0000 +++ src/com/goldencode/p2j/util/handle.java 2021-01-31 10:14:52 +0000 @@ -236,6 +236,7 @@ ** OM 20201030 Invalid attribute API support for getters/setters. ** OM 20201118 Extracted SERIALIZE-HIDDEN into independent interface. ** OM 20201203 Fixed handling of READ/ONLY attributes. +** 126 ME 20210128 Throw instead of force display error for invalid handle access. */ /* @@ -4372,7 +4373,7 @@ if (h.possibleChained) { h.possibleChained = false; - ErrorManager.recordOrShowError(10068); + ErrorManager.recordOrThrowError(10068); // Lead attributes in a chained-attribute expression (a:b:c) must be type HANDLE or a user-defined type and valid (not UNKNOWN). } else === modified file 'src/com/goldencode/p2j/util/longchar.java' --- src/com/goldencode/p2j/util/longchar.java 2020-10-09 15:23:21 +0000 +++ src/com/goldencode/p2j/util/longchar.java 2021-01-28 06:52:32 +0000 @@ -382,7 +382,7 @@ else if (!I18nOps.isSupported(cpToUse)) { ErrorManager.recordOrThrowError(912, - "Code page attribute table for " + cpToUse + " was not found in convmap.p", + "Code page attribute table for " + cpToUse + " was not found in convmap.cp", false); } else === modified file 'src/com/goldencode/p2j/util/object.java' --- src/com/goldencode/p2j/util/object.java 2021-01-13 21:04:41 +0000 +++ src/com/goldencode/p2j/util/object.java 2021-01-31 10:14:52 +0000 @@ -19,8 +19,11 @@ ** GES 20200520 Fixed compareTo() to honor enums (or any other Comparable). ** GES 20200529 Added isTracked() and made all constructors safe for null input. ** GES 20200603 Moved BaseObject legacy class registration into a BaseObject static initializer. -** 007 IAS 20201007 Added Type enum. +** 007 IAS 20201007 Added Type enum ** OM 20201102 Overrode getTypeName(). +** 008 ME 20201106 Delete the object reference when set to unknown (if valid, the destructor is called). +** 20201111 Decrement reference instead of delete when object set to unknown. +** 20201217 Revert compare method to only check if the reference is the same (eq <> Equal in 4GL) */ /* @@ -273,7 +276,7 @@ } else { - return ref.legacyEquals(other).booleanValue() ? 0 : 1; + return ref.equals(other.ref) ? 0 : 1; } } @@ -348,7 +351,15 @@ { if (!(value instanceof object)) { - // TODO: error? + if (value.isUnknown() && !(value instanceof longchar)) + { + setUnknown(); + } + else + { + incompatibleTypesOnConversion(); + } + return; } @@ -460,6 +471,8 @@ */ public void setUnknown() { + if (_isValid()) + ObjectOps.decrement(ref); ref = null; } # Begin bundle IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWQ3c9FMBmqF/gH//Jp7///// /////7////9hrl7w8J5hlWawai9ICDvvvpe68DgM197dy3tmDV3veN2O91wXduPnbTwJ9ChttEAB QAAm7uobcGU5PYGauNxBC23gx19wAAAAAfTQAACgAAaAAHQPg7xPa51fWtddtQ7mne71t7PePTIB 6I28jvZ1ioVvc3r3O151zXtXnOjpTu072928btq86Xx77ffPvh9Wz6NeVXrDsAAR9h7rnGqtlavt 3ZqLOu7KUl2pp97eLp19vvM615u53voj3Ptl9vfbSF93OzsH0k+W1p3e03eedi5ykt73uN294wA8 cd8832br7I7z53SG7ldRfY+eezm9L5nkMw9ypabbQHXu+Tp9enqrvdz7aRTWgB6xPfc597cnaxQi 3p6voKQF92RQH066ALbVAVwCrR1c1K3sc6e+70vXtru4u5witCinjz4vsB99xoffDOvNtUWM7duW 133Nz2G2Muu6c3XYZVUgvi74oBu++na+3U59ucgNj3Goeze2092IUiO+N76gD77zU2GmzewyqSqp BEpEpVfend8APu+93Om7VgCyKBexpVFXm0IkX3W8AHnp2ShqQ1n0alPbW2pCIPjgA763uu7NUvsa SUiUkilR59n30A+77FFVuxoBtgKUL61IFtNwAL16yrTQY+gGkqds2yUD5ux8wx73Po63sm0aAnBs kDtO53K1A67p1xNjtur3t1toR53Tq2d3HS1ts7slXWtmAXY7gZFWkPu5XEyiAi+2X29CuqCWm95K KqVVTusiz2evDvEE1aqjLJmyWVbMBrvKSkIoRBvEAaTqCQUWkgcu9qe8qA7G0bbRA+2aePhAqlXj bGH166atDGAHaffANA7nPtUXjW1rO112+vgSkAVVVT3hArZ5hDee3teXyGjnucefHPUnyYjRqegA odOKT17zXlgBmVKNPvlREVKbBp6cPIoSOhqEChtlZA0Co2oW0GxbbZsZsyIUFsaSloNYrtkcaDNV qo0RgaoNszLIsAAAm2aFNBAAbALUzLBA1SY2wwMqIWCABRNmwtBtgG0qAPbri2KooQlBIBo0gAAA SNbNlsmm1CCQETYZE9uvd2prgHZ9cfffGHGddc0BNMA2BYzUTffY1lUg0B0o8RQxW1EgSWzbFpgQ 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 QlCQ1DUouXDBmUBcNRhgHBO5hDYTAEoniFCh0UE62doFGxSBQGsy4PKU2coddZ3PonBn16SpqR1a 6cyxRDa+9nBqjQ+pbph71R0qolDNK0uuhYPYskLHEu5hqgMAgEIMFeS/54GwGQBICRntsKKIjyCj zQUuzulgB302h1OeAmzDk7eizuqatSHOiLKOP753EQexrWBjINoGvLR7bIZPfTQtJQd4I8nSoWir SbkKsQyn4WqxXpVmxTv08Mc/LL7rbnZdOwmie0NCHEc3gh7a0luebqz8auWgknQkEYgmgfz+39wz x0/vRu++vS5zAkhOKCZY4SfndZvI/ExJIwhUxx+JSCOMC5o1ukZLKLZVvcUGt5VEfBjsPuPcUiqg pcYVcKyrLECo7KzTGBkj+GvmCv4lb9zkTuWRBV84fjxlmneGZY0WZxAM0GT0uehIQJDjaauxJf7R X5zmqIsxJh2gEPV97EkgDgigP1ZAiKIAYld90n9/Q7FgIYkYEf3SIEyN26dRm0SQb4qpQXitjWxl dbmbn09MZhCM8/Dl57OOKAfCnMLaOCdiiioniQaODO1i2jSMkBBBGKCRB17fm/d2O5s9mHi6OrWG G0P9SgH9aZ1gIni+zb+e59QftDMKP+tFJ/Se7/Lc/Sm7cB//RmGlLSpWatlixn2MWY6dCDzcMMw0 3RXk1k5v/vn90nx6IEh5B9RY3d3m5/+VwwPt7fN8+47OXV93h8vntHj4b3X9RgfdD5/TOLD9HmOQ Q/n2ms2d114U47ba8c9cPrhe1O43hFT+1anIf65wNf2RPRsTO/7Zx4PD9nr6f29+5vh7+leF7fw6 8Y6Qi13+rq87qZ+JztR/9v1/l+q222222222222220ttttttlttpbbaW22hbbbbbbbbbbbbbbakk kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkklbbbbbbbbbaW2222222W2220ttttt tLbbbaW22222222222y222222222222220JbbbbbbbbbbbbbbbbbbbbbbbbbS220tpCb18nH2JH+ zza3udM6lAdukSpYln6S9HxdEf8vj2bv8zpQieZc8PZllxWLZw0/6eVGnz3GHv2JM950b7s+jWtc 5z1DzLEQxNq2v6hhAil6Dwya/KlRVtw7KB/kRIhUPq5M3REh7xXtNRY9zt0YMONnHVWKebcwXV8j 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 Uw==