# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: marian.edu@acorn.ro-20210223073932-vu9yjw9avwbx166b # target_branch: sftp://medu@xfer.goldencode.com/opt/fwd/3821c # testament_sha1: 450f4b174962ee6904ef47be4ba59f60512d7730 # timestamp: 2021-02-23 09:41:07 +0200 # base_revision_id: hc@goldencode.com-20210222114705-z9ukxs6lw98hgo6h # # Begin patch === modified file 'src/com/goldencode/p2j/oo/core/ConvCp.java' --- src/com/goldencode/p2j/oo/core/ConvCp.java 2019-10-06 17:20:04 +0000 +++ src/com/goldencode/p2j/oo/core/ConvCp.java 2021-02-05 11:28:05 +0000 @@ -11,6 +11,7 @@ ** 002 CA 20190710 Added LegacyResource annotation. Implemented Equals, NotEquals, IsFalse, ** IsTrue. ** 003 IAS 20190923 Added implementation of additional methods +** 004 ME 20210204 Use upper case when looking-up the codepage. */ /* @@ -199,7 +200,7 @@ { return new character(MIME.stream().collect(Collectors.joining(","))); } - int n = PROGRESS.indexOf(enc.getValue()); + int n = PROGRESS.indexOf(enc.getValue().toUpperCase()); return n < 0 ? enc : new character(MIME.get(n)); } === modified file 'src/com/goldencode/p2j/oo/core/IobjectArrayHolder.java' --- src/com/goldencode/p2j/oo/core/IobjectArrayHolder.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/core/IobjectArrayHolder.java 2021-02-23 07:39:32 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 ME 20200729 Convert from skeleton (OE12.2). +** ME 20210205 Add getter for object array Value. ** 002 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -79,11 +80,14 @@ public interface IobjectArrayHolder extends com.goldencode.p2j.oo.lang._BaseObject_ { + @LegacySignature(returns = "OBJECT", qualified = "Progress.Lang.Object", type = Type.GETTER, name = "Value", extent = -1) + public object[] getValue(); + @LegacySignature(returns = "OBJECT", qualified = "Progress.Lang.Object", type = Type.GETTER, name = "Value", parameters = { @LegacyParameter(name = "idx", type = "INT64", mode = "INPUT") }) - public object getValue_1(final int64 _idx); + public object getValue(final int64 _idx); @LegacySignature(returns = "INTEGER", type = Type.LENGTH, name = "Value") public abstract integer lengthOfValue(); === modified file 'src/com/goldencode/p2j/oo/core/Memptr.java' --- src/com/goldencode/p2j/oo/core/Memptr.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/core/Memptr.java 2021-02-23 07:39:32 +0000 @@ -12,6 +12,7 @@ ** 004 ME 20200331 Fix constructors, add setters and validate input parameters for get methods. ** GES 20200526 Change to match legacy enum implementation. ** 005 CA 20210113 Renamed clear() to clear_(), to follow NameConverter's rules. +** ME 20210204 The class implements ImemptrHolder. ** 006 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -75,6 +76,7 @@ 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.common.support.ImemptrHolder; import com.goldencode.p2j.oo.lang.*; import java.io.IOException; @@ -88,7 +90,7 @@ */ @LegacyResource(resource = "OpenEdge.Core.Memptr") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_PARTIAL) -public class Memptr extends BaseObject +public class Memptr extends BaseObject implements ImemptrHolder { private logical autoDestroy = TypeFactory.logical(); === modified file 'src/com/goldencode/p2j/oo/core/collections/AbstractTtcollection.java' --- src/com/goldencode/p2j/oo/core/collections/AbstractTtcollection.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/core/collections/AbstractTtcollection.java 2021-02-23 07:39:32 +0000 @@ -171,7 +171,7 @@ size.assign(0); tableHandle.assign(p1.unwrapTempTable()); - fieldHandle.assign(p2); + fieldHandle.assign(p2.unwrapBufferField()); })); } === modified file 'src/com/goldencode/p2j/oo/core/collections/ArrayIterator.java' --- src/com/goldencode/p2j/oo/core/collections/ArrayIterator.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/core/collections/ArrayIterator.java 2021-02-23 07:39:32 +0000 @@ -90,7 +90,7 @@ @LegacySignature(type = Type.PROPERTY, name = "IteratedArray") private object iteratedArray = TypeFactory.object(Array.class); - public void __skeleton_oo4gl_openedge_core_collections_ArrayIterator_execute__() + public void __core_collections_ArrayIterator_execute__() { externalProcedure(ArrayIterator.class, ArrayIterator.this, new Block((Body) () -> { @@ -149,7 +149,7 @@ @LegacySignature(type = Type.CONSTRUCTOR, parameters = { @LegacyParameter(name = "poIteratedArray", type = "OBJECT", qualified = "openedge.core.collections.array", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) - public void __skeleton_oo4gl_openedge_core_collections_ArrayIterator_constructor__( + public void __core_collections_ArrayIterator_constructor__( final object _poIteratedArray) { object poIteratedArray = TypeFactory.initInput(_poIteratedArray); === modified file 'src/com/goldencode/p2j/oo/core/collections/IStringStringMap.java' --- src/com/goldencode/p2j/oo/core/collections/IStringStringMap.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/core/collections/IStringStringMap.java 2021-02-23 07:39:32 +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 20200730 Update parameter names. +** ME 20210205 Change second parameter of put method to longchar. ** 004 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -132,7 +133,7 @@ @LegacyParameter(name = "poValue", type = "LONGCHAR", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public longchar put(final character _poKey, final Text _poValue); + public longchar put(final character _poKey, final longchar _poValue); @LegacySignature(returns = "OBJECT", type = Type.METHOD, name = "Put", qualified = "openedge.core.string", parameters = { === modified file 'src/com/goldencode/p2j/oo/core/collections/Imap.java' --- src/com/goldencode/p2j/oo/core/collections/Imap.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/core/collections/Imap.java 2021-02-23 07:39:32 +0000 @@ -10,6 +10,7 @@ ** 002 CA 20191024 Added method support levels and updated the class support level. ** 003 ME 20200729 Update parameter names to match skeleton. ** 004 CA 20210113 Renamed clear() to clear_(), to follow NameConverter's rules. +** 005 ME 20210205 Removed getMap method from interface definition, this is FWD specific. ** 005 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -173,6 +174,4 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void removeAll(final object _poKeys); - public Map getMap(); - } === modified file 'src/com/goldencode/p2j/oo/core/collections/LegacyCollection.java' --- src/com/goldencode/p2j/oo/core/collections/LegacyCollection.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/core/collections/LegacyCollection.java 2021-02-23 07:39:32 +0000 @@ -95,7 +95,7 @@ public class LegacyCollection extends AbstractTtcollection { - private Collection> objects; + private List> objects; public void __core_collections_LegacyCollection_execute__() { @@ -151,10 +151,19 @@ object p1 = TypeFactory.initInput(_p1); return function(this, "Add", logical.class, new Block((Body) () -> { - returnNormal(p1._isValid() && objects.add(p1)); + returnNormal(add_(p1)); })); } + private boolean add_(final object p1) { + if (p1._isValid()) { + ObjectOps.increment(p1.ref()); + return objects.add(p1); + } + + return false; + } + @LegacySignature(returns = "LOGICAL", 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) @@ -164,9 +173,9 @@ object p1[] = TypeFactory.initInput(_p1); return function(this, "AddArray", logical.class, new Block((Body) () -> { - if (p1.length > 0) + for (object obj : p1) { - objects.addAll(Arrays.asList(p1)); + add_(obj); } returnNormal(true); @@ -184,7 +193,10 @@ 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); + for (object obj : ObjectOps.cast(p1, LegacyCollection.class).ref().objects) + { + add_(obj); + } returnNormal(true); } else @@ -224,20 +236,28 @@ protected object _find( final object checkObject) { - // in 4GL objects are also matched using equals (LegacyEquals) if (checkObject._isValid()) { - if (objects.contains(checkObject)) - return checkObject; - + List> items = objects.stream() + .filter(o -> o.equals(checkObject)).collect(Collectors.toList()); + + // if more objects found (duplicate) 4GL sees it as ambiguous + if (items.size() == 1) + { + return items.get(0); + } + + // in 4GL objects are also matched using equals (LegacyEquals) Optional> found = objects.stream() .filter(o -> checkObject.ref().legacyEquals(o).booleanValue()).findFirst(); if (found.isPresent()) + { return found.get(); + } } - return checkObject; + return TypeFactory.object(_BaseObject_.class); } @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "ContainsAll", parameters = { === modified file 'src/com/goldencode/p2j/oo/core/collections/LegacyIterator.java' --- src/com/goldencode/p2j/oo/core/collections/LegacyIterator.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/core/collections/LegacyIterator.java 2021-02-23 07:39:32 +0000 @@ -336,7 +336,7 @@ } else if (qry.getNumResults().intValue() == 1 && qry.currentRow().intValue() == 1) { - returnNormal(bufferHandle.unwrapBuffer().available()); + returnNormal(!bufferHandle.unwrapBuffer().available().booleanValue()); } else { @@ -373,14 +373,14 @@ else { queryHandle.unwrapQuery().next(); + object<_BaseObject_> ret = TypeFactory.object(_BaseObject_.class); + if (bufferHandle.unwrapBuffer()._available()) { - returnNormal(objectFieldHandle.unwrapBufferField().value()); - } - else - { - returnNormal(new object<>()); - } + ret.assign(objectFieldHandle.unwrapBufferField().value()); + } + + returnNormal(ret); } })); } === modified file 'src/com/goldencode/p2j/oo/core/collections/LegacyMap.java' --- src/com/goldencode/p2j/oo/core/collections/LegacyMap.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/core/collections/LegacyMap.java 2021-02-23 07:39:32 +0000 @@ -8,6 +8,7 @@ ** 001 ME 20200427 First version, stubs taken by converting the skeleton using FWD. ** 002 CA 20210113 Renamed Iiterator.next to Iiterator.next_, to follow NameConverter's rules. ** Renamed clear() to clear_(), to follow NameConverter's rules. +** ME 20210205 Removed getMap method from interface definition, this is FWD specific. ** 003 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -451,7 +452,6 @@ })); } - @Override public Map getMap() { return map; === modified file 'src/com/goldencode/p2j/oo/core/collections/StringStringMap.java' --- src/com/goldencode/p2j/oo/core/collections/StringStringMap.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/core/collections/StringStringMap.java 2021-02-23 07:39:32 +0000 @@ -6,6 +6,7 @@ ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 ME 20200427 First version, stubs taken by converting the skeleton using FWD. +** ME 20210205 Change second parameter of put method to longchar. ** ** 002 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. @@ -297,7 +298,7 @@ @LegacyParameter(name = "pcKey", type = "CHARACTER", mode = "INPUT"), @LegacyParameter(name = "pcValue", type = "LONGCHAR", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) - public longchar put(final character pcKey, final Text pcValue) + public longchar put(final character pcKey, final longchar pcValue) { return function(StringStringMap.class, this, "Put", longchar.class, new Block((Body) () -> { object key = ObjectOps.newInstance(LegacyString.class, "I", pcKey); === modified file 'src/com/goldencode/p2j/oo/io/FileInputStream.java' --- src/com/goldencode/p2j/oo/io/FileInputStream.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/io/FileInputStream.java 2021-02-23 07:39:32 +0000 @@ -9,6 +9,7 @@ ** 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. +** ME 20210204 Complete implementation as of OE12.2. ** 005 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -74,7 +75,9 @@ import static com.goldencode.p2j.util.BlockManager.onBlockLevel; import static com.goldencode.p2j.report.ReportConstants.*; import static com.goldencode.p2j.util.BlockManager.returnNormal; +import static com.goldencode.p2j.util.BlockManager.undoThrow; +import com.goldencode.p2j.oo.lang.SysError; import com.goldencode.p2j.util.*; import com.goldencode.p2j.util.BlockManager.Action; import com.goldencode.p2j.util.BlockManager.Condition; @@ -85,14 +88,18 @@ * in Progress/IO/FileInputStream.cls). */ @LegacyResource(resource = "Progress.IO.FileInputStream") -@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) +@LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public class FileInputStream extends InputStream { @LegacySignature(type = Type.PROPERTY, name = "FileName") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) private character fileName = TypeFactory.character(); - + private long fileSize; + private long bytesLeft; + + private Stream sFileStream = new StreamWrapper("sFile"); + public void __io_FileInputStream_execute__() { externalProcedure(FileInputStream.class, FileInputStream.this, new Block((Body) () -> @@ -107,7 +114,7 @@ { @LegacyParameter(name = "filename", type = "CHARACTER", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void __io_FileInputStream_constructor__(final character _filename) { character filename = TypeFactory.initInput(_filename); @@ -115,12 +122,34 @@ internalProcedure(FileInputStream.class, this, "__io_FileInputStream_constructor__", new Block((Body) () -> { __io_InputStream_constructor__(); + + if (filename.isUnknown()) + { + undoThrow(SysError.newInstance("Invalid file name specified for 'Progress.IO.FileInputStream'", 18195, false, false)); + } + this.fileName.assign(filename); + + try + { + sFileStream.assign(StreamFactory.openFileStream((filename).toStringMessage(), false, false)); + sFileStream.setBinary(); + sFileStream.setConvert(false); + + FileSystemOps.initFileInfo(fileName); + fileSize = FileSystemOps.fileInfoGetSize().longValue(); + bytesLeft = fileSize; + } + catch (Exception e) + { + undoThrow(SysError.newInstance("Cannot find or open file %s, errno = 2", 11294, true, false)); + } + })); } @LegacySignature(returns = "CHARACTER", type = Type.GETTER, name = "FileName") - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public character getFileName() { return function(FileInputStream.class, this, "FileName", character.class, new Block((Body) () -> @@ -131,12 +160,13 @@ @LegacySignature(type = Type.METHOD, name = "Close") @Override - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public void close() { internalProcedure(FileInputStream.class, this, "Close", new Block((Body) () -> { - UnimplementedFeature.missing("FileInputStream:Close METHOD"); + sFileStream.closeIn(); + super.close(); })); } @@ -145,14 +175,12 @@ @LegacyParameter(name = "target", type = "MEMPTR", mode = "INPUT") }) @Override - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) - public int64 read(final memptr _target) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public int64 read(final memptr target) { - memptr target = TypeFactory.initInput(_target); - return function(FileInputStream.class, this, "Read", int64.class, new Block((Body) () -> { - UnimplementedFeature.missing("FileInputStream:Read1 METHOD"); + returnNormal(read(target, new int64(1), target.length())); })); } @@ -161,14 +189,37 @@ @LegacyParameter(name = "n", type = "INT64", mode = "INPUT") }) @Override - @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 mdata = TypeFactory.memptr(); return function(FileInputStream.class, this, "SkipBytes", int64.class, new Block((Body) () -> { - UnimplementedFeature.missing("FileInputStream:SkipBytes METHOD"); + if (getClosed().booleanValue()) + { + undoThrow(SysError.newInstance("Cannot invoke method 'SkipBytes' after stream has been closed", 18196, false, false)); + } + + if (n.isUnknown()) + { + undoThrow(SysError.newInstance("Invalid value specified for parameter 'length' of method or constructor 'SkipBytes'", 18193, false, true)); + } + + if (n.longValue() < 1) + { + returnNormal(0); + } + + mdata.setLength(n); + + read(mdata); + + returnNormal(n); + + }, (Fini) () -> { + mdata.setLength(0); })); } @@ -179,16 +230,66 @@ @LegacyParameter(name = "length", type = "INT64", mode = "INPUT") }) @Override - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public int64 read(final memptr _target, final int64 _offset, final int64 _length) { memptr target = TypeFactory.initInput(_target); int64 offset = TypeFactory.initInput(_offset); int64 length = TypeFactory.initInput(_length); + memptr vmem = TypeFactory.memptr(); return function(FileInputStream.class, this, "Read", int64.class, new Block((Body) () -> { - UnimplementedFeature.missing("FileInputStream:Read2 METHOD"); + if (getClosed().booleanValue()) + { + undoThrow(SysError.newInstance("Cannot invoke method 'Read' after stream has been closed", 18196, false, false)); + } + + if (target.length().longValue() == 0) + { + undoThrow(SysError.newInstance("Invalid parameter: An initialized MEMPTR must be provided for the Read method or constructor", 19066, false, true)); + } + + if (offset.isUnknown() || offset.longValue() < 1 || offset.longValue() > target.length().longValue()) + { + undoThrow(SysError.newInstance("Invalid value specified for parameter 'offset' of method or constructor 'Read'", 18193, false, true)); + } + + if (length.isUnknown() || length.longValue() < 0) + { + undoThrow(SysError.newInstance("Invalid value specified for parameter 'length' of method or constructor 'Read'", 18193, false, true)); + } + + long toRead = bytesLeft; + + if (bytesLeft > 0) + { + toRead = Math.min(bytesLeft, Math.min(length.longValue(), target.length().longValue() + 1 - offset.longValue())); + } + + // easy way out + if (toRead > 0) + { + bytesLeft -= toRead; + + // read straight into the given memptr + if (offset.longValue() == 1 && toRead == target.length().longValue()) + { + sFileStream.readBlock(target); + } + else + { + vmem.setLength(toRead); + sFileStream.readBlock(vmem); + target.setBytes(vmem, offset); + } + + sFileStream.resetCurrentLine(); + } + + returnNormal(toRead); + }, (Fini) () -> { + vmem.setLength(0); })); } @@ -198,18 +299,12 @@ @LegacyParameter(name = "target", type = "CHARACTER", mode = "OUTPUT") }) @Override - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public int64 read(final character _delimiter, final character target) { - character delimiter = TypeFactory.initInput(_delimiter); - - return function(FileInputStream.class, this, "Read", int64.class, new Block((Init) () -> - { - TypeFactory.initOutput(target); - }, - (Body) () -> - { - UnimplementedFeature.missing("FileInputStream:Read3 METHOD"); + return function(FileInputStream.class, this, "Read", int64.class, new Block((Body) () -> + { + undoThrow(SysError.newInstance("Cannot invoke Read method in 'Progress.IO.FileInputStream' because it is not implemented", 18192, false, false)); })); } @@ -219,18 +314,16 @@ @LegacyParameter(name = "target", type = "LONGCHAR", mode = "OUTPUT") }) @Override - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public int64 read(final character _delimiter, final longchar target) { - character delimiter = TypeFactory.initInput(_delimiter); - return function(FileInputStream.class, this, "Read", int64.class, new Block((Init) () -> { TypeFactory.initOutput(target); }, (Body) () -> { - UnimplementedFeature.missing("FileInputStream:Read4 METHOD"); + undoThrow(SysError.newInstance("Cannot invoke Read method in 'Progress.IO.FileInputStream' because it is not implemented", 18192, false, false)); })); } } === modified file 'src/com/goldencode/p2j/oo/io/InputStream.java' --- src/com/goldencode/p2j/oo/io/InputStream.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/io/InputStream.java 2021-02-23 07:39:32 +0000 @@ -8,6 +8,7 @@ ** 001 IAS 20190923 First version. ** 002 MP 20200703 Complete code with methods like legacy class ** 003 ME 20201209 Fully implement non-abstract methods. +** ME 20210204 Add destructor to automatically close the stream. ** 004 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -112,6 +113,16 @@ __lang_BaseObject_constructor__(); })); } + + @LegacySignature(type = Type.DESTRUCTOR) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public void __io_InputStream_destructor__() + { + internalProcedure(this, "__io_InputStream_destructor__", new Block((Body) () -> + { + close(); + })); + } @LegacySignature(returns = "LOGICAL", type = Type.GETTER, name = "Closed") @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) === modified file 'src/com/goldencode/p2j/oo/json/JsonBackend.java' --- src/com/goldencode/p2j/oo/json/JsonBackend.java 2021-01-29 08:33:05 +0000 +++ src/com/goldencode/p2j/oo/json/JsonBackend.java 2021-02-15 09:22:31 +0000 @@ -8,6 +8,7 @@ ** 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. + ** 20210215 Extend pretty printer to match the 4GL formated output. */ /* @@ -70,11 +71,13 @@ import com.fasterxml.jackson.core.io.SerializedString; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.util.*; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter.Indenter; import com.goldencode.p2j.oo.json.objectmodel.*; import com.goldencode.p2j.util.*; import java.io.*; import java.math.*; +import java.nio.charset.Charset; import java.util.*; /** @@ -139,17 +142,23 @@ JsonGenerator gen = factory.createGenerator(target, enc); if (prettyPrint) { - // TODO: there are some small differences how 4GL formats the output, - // for example new object bracket as the first element in an array is - // put on new line - gen.setPrettyPrinter(new DefaultPrettyPrinter()); + gen.setPrettyPrinter(ProPretyPrinter.instance()); } // 4GL escapes forward slash - gen.setCharacterEscapes(new ProCharacterEscapes()); + gen.setCharacterEscapes(ProCharacterEscapes.instance()); writeConstruct(gen, construct); gen.flush(); - gen.close(); + + // skip this as it will close the stream and not always what we need + // gen.close(); + + // 4GL add a new line at the end of document + if (prettyPrint) + { + target.write("\n".getBytes(Charset.forName(enc.getJavaName()))); + } + return enc.getJavaName(); } @@ -540,13 +549,18 @@ } } - private class ProCharacterEscapes extends CharacterEscapes { + private static class ProCharacterEscapes extends CharacterEscapes { private static final long serialVersionUID = 1L; + private static final ProCharacterEscapes _escapeInstance = new ProCharacterEscapes(); + + public static ProCharacterEscapes instance() { return _escapeInstance; } + + private final SerializedString fwdSlash; private final int[] asciiEscapes; - public ProCharacterEscapes() + private ProCharacterEscapes() { fwdSlash = new SerializedString("\\/"); asciiEscapes = standardAsciiEscapesForJSON(); @@ -568,6 +582,52 @@ return null; } + } + + private static class ProPretyPrinter extends DefaultPrettyPrinter { + private static final long serialVersionUID = 1L; + private static final ProPretyPrinter _printerInstance = new ProPretyPrinter(); + + public static ProPretyPrinter instance() { return _printerInstance; } + + ProPretyPrinter() { + indentArraysWith(TwoSpacesIndenter.instance()); + indentObjectsWith(TwoSpacesIndenter.instance()); + } + + @Override + public void writeObjectFieldValueSeparator(JsonGenerator g) throws IOException + { + // no space between name and colon + g.writeRaw(": "); + } + + } + + private static class TwoSpacesIndenter implements Indenter + { + + private static final TwoSpacesIndenter _indenterInstance = new TwoSpacesIndenter(); + + public static TwoSpacesIndenter instance() { return _indenterInstance; } + + @Override + public boolean isInline() + { + return false; + } + + @Override + public void writeIndentation(JsonGenerator g, int level) throws IOException + { + g.writeRaw('\n'); + + for (int i = 0; i < level; i++) + { + g.writeRaw(" "); + } + + } } } === modified file 'src/com/goldencode/p2j/oo/json/objectmodel/JsonArray.java' --- src/com/goldencode/p2j/oo/json/objectmodel/JsonArray.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/json/objectmodel/JsonArray.java 2021-02-23 07:39:32 +0000 @@ -13,6 +13,7 @@ ** 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. +** 20210215 Fix write method return. ** 009 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -3036,7 +3037,6 @@ /** * Removes all values from this json object or array. */ - @Override protected void clear() { for (Object o : elements) @@ -3366,9 +3366,7 @@ }) public logical read(final handle htt) { - return function(this, "Read", logical.class, new Block((Body) () -> { - returnNormal(read(htt, new logical(false))); - })); + return read(htt, new logical(false)); } @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Read", parameters = @@ -3382,8 +3380,9 @@ logical omit = TypeFactory.initInput(_omit); return function(this, "Read", logical.class, new Block((Body) () -> { + logical ret = TypeFactory.logical(); - if (!htt._isValid() || !CompareOps._isEqual(htt.unwrapType().getResourceType(), "temp-table")) + if (!htt._isValid() || !htt.isType("TEMP-TABLE")) { undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("temp-table handle", this, "Read", "Not initialized or not a handle to a TEMP-TABLE."), 16070)); @@ -3400,13 +3399,15 @@ try { export.serializeTempTable(jb, tmpBuffer, !omit.isUnknown() && omit.booleanValue()); - returnNormal(new logical(true)); + ret.assign(true); } catch (Exception e) { log.log(Level.WARNING, "", e); returnError(ObjectOps.newInstance(JsonError.class)); } + + returnNormal(ret); })); } } === modified file 'src/com/goldencode/p2j/oo/json/objectmodel/JsonConstruct.java' --- src/com/goldencode/p2j/oo/json/objectmodel/JsonConstruct.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/json/objectmodel/JsonConstruct.java 2021-02-23 07:39:32 +0000 @@ -2,7 +2,7 @@ ** Module : JsonConstruct.java ** Abstract : Implementation of the Progress.Json.Objectmodel.JsonConstruct builtin class. ** -** Copyright (c) 2018-2021, Golden Code Development Corporation. +** Copyright (c) 2018-2020, Golden Code Development Corporation. ** ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 OM 20181218 First version. @@ -21,6 +21,8 @@ ** 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. +** 20210209 Fix encoding parameter sent to write method (unknown instead of null). +** 20210215 Remove clean/read methods, refactor write. ** 012 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -82,16 +84,15 @@ import com.goldencode.p2j.oo.json.*; import com.goldencode.p2j.oo.lang.*; -import com.goldencode.p2j.persist.*; import com.goldencode.p2j.persist.serial.*; 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.nio.charset.*; import java.util.*; -import java.util.function.*; import java.util.logging.*; import static com.goldencode.p2j.util.BlockManager.*; @@ -141,44 +142,24 @@ })); } - @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Read", parameters = - { - @LegacyParameter(name = "tt", type = "HANDLE", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public logical read(final TableParameter _tt) - { - return read(_tt, new logical(false)); - } - - @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Read", parameters = - { - @LegacyParameter(name = "tt", type = "HANDLE", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_NONE) - public logical read(final handle _tt) - { - UnimplementedFeature.missing("JsonConstruct:read(handle)"); - return new logical(false); - } - - @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Read", parameters = - { - @LegacyParameter(name = "tt", type = "HANDLE", mode = "INPUT"), - @LegacyParameter(name = "omit", type = "LOGICAL", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public logical read(final TableParameter _tt, final logical _omit) - { - logical omit = TypeFactory.initInput(_omit); - - return function(this, "Read", logical.class, new Block((Body) () -> - { - TemporaryBuffer tb = (TemporaryBuffer) ((BufferReference) _tt.getTable()).buffer(); - readImpl(tb, omit); - })); - } - + /** + * Writes the object graph referenced by this JSON construct into the given target. + * + * @param _strHndl + * The stream handle to use as a target. + * + * @return {@code true} if the serialization was successful. + */ + @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Write", parameters = + { + @LegacyParameter(name = "str-hndl", type = "HANDLE", mode = "INPUT"), + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public logical write(final handle strHndl) + { + return write(strHndl, new logical(false), new character()); + } + /** * Writes the object graph referenced by this JSON construct into the given target. * @@ -195,15 +176,9 @@ @LegacyParameter(name = "fmtted", type = "LOGICAL", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public logical write(final handle _strHndl, final logical _fmtted) + public logical write(final handle strHndl, final logical fmtted) { - handle strHndl = TypeFactory.initInput(_strHndl); - logical fmtted = TypeFactory.initInput(_fmtted); - - return function(this, "Write", logical.class, new Block((Body) () -> - { - write(strHndl, fmtted, new character()); - })); + return write(strHndl, fmtted, new character()); } /** @@ -234,18 +209,18 @@ return function(this, "Write", logical.class, new Block((Body) () -> { Stream stream = (Stream) strHndl.getResource(); - writeImpl(fmtted, enc, (b, chset) -> + OutputStream o = new OutputStreamWrapper(stream); + logical ret = TypeFactory.logical(); + + try { + writeImpl(o, fmtted, enc); + ret.assign(true); + } + catch (Exception e) { - try - { - stream.write(b); - return new logical(true); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - }); + returnError(JsonError.newInstance(e.getMessage(), 0)); + } + returnNormal(ret); })); } @@ -262,16 +237,9 @@ @LegacyParameter(name = "target", type = "LONGCHAR", mode = "INPUT-OUTPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public logical write_1(final longchar target) + public logical write(final longchar target) { - return function(this, "Write", logical.class, new Block((Body) () -> - { - writeImpl(null, null, (b, chset) -> - { - target.assign(new String(b, chset)); - return new logical(true); - }); - })); + return write(target, new logical(false), new character()); } /** @@ -290,18 +258,9 @@ @LegacyParameter(name = "fmtted", type = "LOGICAL", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public logical write(final longchar target, final logical _fmtted) + public logical write(final longchar target, final logical fmtted) { - logical fmtted = TypeFactory.initInput(_fmtted); - - return function(this, "Write", logical.class, new Block((Body) () -> - { - writeImpl(fmtted, null, (b, chset) -> - { - target.assign(new String(b, chset)); - return new logical(true); - }); - })); + return write(target, fmtted, new character()); } /** @@ -330,11 +289,27 @@ return function(this, "Write", logical.class, new Block((Body) () -> { - writeImpl(fmtted, enc, (b, chset) -> - { - target.assign(new String(b, chset)); - return new logical(true); - }); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + logical ret = TypeFactory.logical(); + + if (TextOps.isEmpty(enc)) + { + enc.assign("UTF-8"); + } + + try { + Charset ch = writeImpl(out, fmtted, enc); + target.setUnknown(); + target.fixCodePage(enc); + target.assign(new String(out.toByteArray(), ch)); + ret.assign(true); + } + catch (Exception e) + { + returnError(JsonError.newInstance(e.getMessage(), 0)); + } + + returnNormal(ret); })); } @@ -353,10 +328,7 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public logical write(final memptr _target) { - return function(this, "Write", logical.class, new Block((Body) () -> - { - returnNormal(write(_target, null, null)); - })); + return write(_target, new logical(false), new character()); } /** @@ -377,12 +349,7 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public logical write(final memptr _target, final logical _fmtted) { - logical fmtted = TypeFactory.initInput(_fmtted); - - return function(this, "Write", logical.class, new Block((Body) () -> - { - returnNormal(write(_target, fmtted, null)); - })); + return write(_target, _fmtted, new character()); } /** @@ -411,11 +378,22 @@ return function(this, "Write", logical.class, new Block((Body) () -> { - writeImpl(fmtted, enc, (b, chset) -> + ByteArrayOutputStream out = new ByteArrayOutputStream(); + logical ret = TypeFactory.logical(); + + try { + Charset ch = writeImpl(out, fmtted, enc); + _target.setLength(0); + _target.setLength(out.size()); + _target.write(true, out.toByteArray(), 0, false); + + ret.assign(true); + } + catch (Exception e) { - _target.assign(b); - return new logical(true); - }); + returnError(JsonError.newInstance(e.getMessage(), 0)); + } + returnNormal(ret); })); } @@ -434,7 +412,7 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public logical write(final character target) { - return write(target, new logical(false)); + return write(target, new logical(false), new character()); } /** @@ -484,11 +462,20 @@ return function(this, "Write", logical.class, new Block((Body) () -> { - writeImpl(fmtted, enc, (b, chset) -> + ByteArrayOutputStream out = new ByteArrayOutputStream(); + logical ret = TypeFactory.logical(); + + try { + Charset ch = writeImpl(out, fmtted, enc); + target.assign(new String(out.toByteArray(), ch)); + ret.assign(true); + } + catch (Exception e) { - target.assign(new String(b, chset)); - return new logical(true); - }); + returnError(JsonError.newInstance(e.getMessage(), 0)); + } + + returnNormal(ret); })); } @@ -552,32 +539,35 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public logical writeFile(final character _fname, final logical _fmtted, final character _enc) { + character fname = TypeFactory.initInput(_fname); logical fmtted = TypeFactory.initInput(_fmtted); character enc = TypeFactory.initInput(_enc); - return function(this, "Write", logical.class, new Block((Body) () -> + return function(this, "WriteFile", logical.class, new Block((Body) () -> { - writeImpl(fmtted, enc, (b, chset) -> - { - Stream s = StreamFactory.openFileStream(_fname.toStringMessage(), true, false); - if (s == null) - { - return new logical(false); - } - else - { - try - { - s.write(b); - s.close(); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - return new logical(true); - } - }); + if (TextOps.isEmpty(fname)) + { + undoThrow(JsonError.newInstance(ErrorManager.getInvalidParameterError("filename", this, + "WriteFile", "Can not be UNKNOWN (?) or empty string."), 16055)); + } + + Stream s = StreamFactory.openFileStream(fname.toStringMessage(), true, false); + OutputStream o = new OutputStreamWrapper(s); + logical ret = TypeFactory.logical(); + + try { + writeImpl(o, fmtted, enc); + + ret.assign(true); + } + catch (Exception e) + { + returnError(JsonError.newInstance(e.getMessage(), 0)); + } finally { + s.closeOut(); + } + + returnNormal(ret); })); } @@ -647,35 +637,28 @@ return function(this, "WriteStream", logical.class, new Block((Body) () -> { - if (sname.isUnknown()) - { - returnError(ObjectOps.newInstance(JsonError.class)); - } - else - { - Stream s = StreamFactory.findOutputStream(sname.toStringMessage()); - if (s == null) - { - returnNormal(new logical(false)); - } - else - { - boolean pretty = fmtted != null && !fmtted.isUnknown() && fmtted.booleanValue(); - OutputStream o = new OutputStreamWrapper(s); - try - { - JsonBackend.instance().write(o, - this, pretty, - enc.isUnknown() ? null : enc.toStringMessage()); - returnNormal(new logical(true)); - } - catch (IOException e) - { - log.log(Level.WARNING, "", e); - returnError(ObjectOps.newInstance(JsonError.class)); - } - } - } + logical ret = TypeFactory.logical(); + Stream s = StreamFactory.findOutputStream(sname.isUnknown() ? null : sname.toStringMessage()); + if (s != null) + { + boolean pretty = fmtted != null && !fmtted.isUnknown() && fmtted.booleanValue(); + OutputStream o = new OutputStreamWrapper(s); + + try + { + JsonBackend.instance().write(o, + this, pretty, + enc.isUnknown() ? null : enc.toStringMessage()); + ret.assign(true); + } + catch (Exception e) + { + log.log(Level.WARNING, "", e); + returnError(ObjectOps.newInstance(JsonError.class)); + } + } + + returnNormal(ret); })); } @@ -739,37 +722,15 @@ * @param converter * Bi function instance that will receive the serialized bytes and return {@code BaseDateType} * value that will be "returned" with the call to {@link BlockManager#returnNormal}. + * @throws Exception */ - protected void writeImpl(logical fmted, character enc, BiFunction converter) + protected Charset writeImpl(OutputStream out, logical fmted, character enc) throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); boolean pretty = fmted != null && !fmted.isUnknown() && fmted.booleanValue(); String legacyEnc = enc != null && !enc.isUnknown() ? enc.toStringMessage() : null; - try - { - String javaEnc = JsonBackend.instance().write(out, this, pretty, legacyEnc); - returnNormal(converter.apply(out.toByteArray(), Charset.forName(javaEnc))); - } - catch (UnsupportedEncodingException e) - { - log.log(Level.WARNING, "", e); - returnError(ObjectOps.newInstance(JsonError.class)); - } - catch (IOException e) - { - log.log(Level.WARNING, "", e); - returnError(ObjectOps.newInstance(JsonError.class)); - } - catch (StackUnwindException e) - { - throw e; - } - catch (RuntimeException e) - { - log.log(Level.WARNING, "", e); - returnError(ObjectOps.newInstance(JsonError.class)); - } + return Charset.forName(JsonBackend.instance().write(out, this, pretty, legacyEnc)); + } /** @@ -834,37 +795,6 @@ } /** - * Implements the method {@link #read(TableParameter)} and {@link #read(TableParameter, logical)} for - * json object and array classes. - * - * @param tb - * Temp buffer to read. - * @param omit - * {@code true} to omit initial values, {@code false} otherwise. - */ - protected void readImpl(TemporaryBuffer tb, final logical omit) - { - ObjectBuilder jb = new ObjectBuilder(this); - clear(); - JsonExport export = new JsonExport(); - try - { - export.exportTempBuffer(tb, omit, new logical(false), jb); - returnNormal(new logical(true)); - } - catch (PersistenceException e) - { - log.log(Level.WARNING, "", e); - returnError(ObjectOps.newInstance(JsonError.class)); - } - } - - /** - * Removes all values from this json object or array. - */ - protected abstract void clear(); - - /** * Json structure callback for building the json objects. */ protected static class ObjectBuilder === modified file 'src/com/goldencode/p2j/oo/json/objectmodel/JsonObject.java' --- src/com/goldencode/p2j/oo/json/objectmodel/JsonObject.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/json/objectmodel/JsonObject.java 2021-02-23 07:39:32 +0000 @@ -16,7 +16,8 @@ ** 007 HC 20190803 Fixed an NPE condition in read(). ** 008 CA 20191024 Added method support levels and updated the class support level. ** 009 CA 20191013 read(handle) can load either a TEMP-TABLE or DATASET. -** 010 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy +** 010 ME 20210215 Fixing read methods. +** 011 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -79,8 +80,9 @@ import com.goldencode.p2j.oo.lang.*; import com.goldencode.p2j.persist.*; import com.goldencode.p2j.persist.serial.*; -import com.goldencode.p2j.ui.chui.*; import com.goldencode.p2j.util.*; +import com.goldencode.p2j.util.BlockManager.Action; +import com.goldencode.p2j.util.BlockManager.Condition; import java.io.*; import java.time.format.*; @@ -114,8 +116,7 @@ { externalProcedure(JsonObject.this, new Block((Body) () -> { - { - } + onBlockLevel(Condition.ERROR, Action.THROW); })); } @@ -901,63 +902,12 @@ @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Read", parameters = { - @LegacyParameter(name = "pds", type = "HANDLE", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public logical read(final DataSetParameter _pds) - { - return read(_pds, new logical(false)); - } - - @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Read", parameters = - { - @LegacyParameter(name = "pds", type = "HANDLE", mode = "INPUT"), - @LegacyParameter(name = "omit", type = "LOGICAL", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public logical read(final DataSetParameter _pds, final logical _omit) - { - return read(_pds, _omit, new logical(false)); - } - - @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Read", parameters = - { - @LegacyParameter(name = "pds", type = "HANDLE", mode = "INPUT"), - @LegacyParameter(name = "omit", type = "LOGICAL", mode = "INPUT"), - @LegacyParameter(name = "b4img", type = "LOGICAL", mode = "INPUT") - }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) - public logical read(final DataSetParameter _pds, final logical _omit, final logical _b4img) - { - logical omit = TypeFactory.initInput(_omit); - logical b4img = TypeFactory.initInput(_b4img); - - return function(this, "Read", logical.class, new Block((Init) () -> - { - ObjectBuilder jb = new ObjectBuilder(this); - properties.clear(); - try - { - JsonExport export = new JsonExport(); - export.exportDataSet(_pds.getDataset(), false, omit.booleanValue(), b4img.booleanValue(), jb); - returnNormal(new logical(true)); - } - catch (PersistenceException e) - { - log.log(Level.WARNING, "", e); - returnError(ObjectOps.newInstance(JsonError.class)); - } - })); - } - - @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Read", parameters = - { @LegacyParameter(name = "bh", type = "HANDLE", mode = "INPUT") }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public logical read(final handle _bh) { - return read(_bh, new logical(false)); + return read(_bh, new logical(false), new logical(false)); } @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Read", parameters = @@ -968,9 +918,22 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public logical read(final handle _bh, final logical _omit) { + return read(_bh, _omit, new logical(false)); + } + + @LegacySignature(returns = "LOGICAL", type = Type.METHOD, name = "Read", parameters = + { + @LegacyParameter(name = "bh", type = "HANDLE", mode = "INPUT"), + @LegacyParameter(name = "omit", type = "LOGICAL", mode = "INPUT"), + @LegacyParameter(name = "b4img", type = "LOGICAL", mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public logical read(final handle _bh, final logical _omit, final logical _b4img) + { handle bh = TypeFactory.initInput(_bh); logical omit = TypeFactory.initInput(_omit); - + logical b4img = TypeFactory.initInput(_b4img); + return function(this, "Read", logical.class, new Block((Init) () -> { if (!bh.isUnknown()) @@ -980,12 +943,18 @@ { BufferImpl buf = (BufferImpl) res; TemporaryBuffer tb = (TemporaryBuffer) buf.buffer(); - readImpl(tb, omit); + returnNormal(readImpl(tb, omit)); + } + else if (res instanceof TempTable) + { + TempTable tt = (TempTable) res; + TemporaryBuffer tb = (TemporaryBuffer) ((BufferImpl) tt.defaultBufferHandle().getResource()).buffer(); + returnNormal(readImpl(tb, omit)); } else if (res instanceof DataSet) { DataSet ds = (DataSet) res; - read(new DataSetParameter(ds), omit); + returnNormal(readImpl(ds, omit, b4img)); } else { @@ -1427,7 +1396,6 @@ /** * Removes all values from this json object or array. */ - @Override protected void clear() { for (Map.Entry e : properties.entrySet()) @@ -1598,4 +1566,46 @@ returnError(ObjectOps.newInstance(JsonError.class)); } } + + protected logical readImpl(TemporaryBuffer tb, final logical omit) + { + return function(this, "Read", logical.class, new Block((Body) () -> { + ObjectBuilder jb = new ObjectBuilder(this); + JsonExport export = new JsonExport(); + + try + { + export.exportTempBuffer(tb, omit, new logical(false), jb); + returnNormal(new logical(true)); + } + catch (PersistenceException e) + { + log.log(Level.WARNING, "", e); + returnError(ObjectOps.newInstance(JsonError.class)); + } + })); + } + + protected logical readImpl(DataSet pds, final logical omit, final logical b4img) + { + return function(this, "Read", logical.class, new Block((Body) () -> { + ObjectBuilder jb = new ObjectBuilder(this); + JsonExport export = new JsonExport(); + + try + { + export.exportDataSet(pds, false, + !omit.isUnknown() && omit.booleanValue(), + !b4img.isUnknown() && b4img.booleanValue(), + jb); + + returnNormal(new logical(true)); + } + catch (PersistenceException e) + { + log.log(Level.WARNING, "", e); + returnError(ObjectOps.newInstance(JsonError.class)); + } + })); + } } === modified file 'src/com/goldencode/p2j/oo/lang/BaseObject.java' --- src/com/goldencode/p2j/oo/lang/BaseObject.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/lang/BaseObject.java 2021-02-23 07:39:32 +0000 @@ -17,6 +17,7 @@ ** 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). +** 20210209 Revert changes, removed hashCode/equals method. ** 009 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -235,25 +236,4 @@ { 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/SysError.java' --- src/com/goldencode/p2j/oo/lang/SysError.java 2021-01-15 11:17:07 +0000 +++ src/com/goldencode/p2j/oo/lang/SysError.java 2021-02-05 11:28:05 +0000 @@ -11,6 +11,7 @@ ** 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. +** ME 20210204 Add API to create instances using 'build message' (prefix, dot). */ /* @@ -158,4 +159,20 @@ return ObjectOps.newInstance(SysError.class, "II", msg, num); } + /** + * Create a new SysError instance and return it as a legacy object. + * + * @param msg + * The error message. + * @param num + * The error number. + * @param prefix + * Prefix with two stars when building the error message. + * @param addDot + * The dot when building the error message. + */ + public static object newInstance(String msg, int num, boolean prefix, boolean addDot) + { + return ObjectOps.newInstance(SysError.class, "II", ErrorManager.buildErrorText(num, msg, prefix, addDot), num); + } } === modified file 'src/com/goldencode/p2j/oo/net/Uri.java' --- src/com/goldencode/p2j/oo/net/Uri.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/Uri.java 2021-02-23 07:39:32 +0000 @@ -14,6 +14,7 @@ ** 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. +** ME 20210205 Use a StringStringMap variable to access the internal map, use longchar for put method. ** 007 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -187,8 +188,8 @@ // default unknown private integer port = new integer(); - private object queryMap = TypeFactory - .object(com.goldencode.p2j.oo.core.collections.IStringStringMap.class); + private object queryMap = TypeFactory + .object(com.goldencode.p2j.oo.core.collections.StringStringMap.class); private character scheme = TypeFactory.character(); @@ -757,7 +758,7 @@ internalProcedure(this, "AddQuery", new Block((Body) () -> { Assert.notNullOrEmpty(p1, new character("Query name")); - getQueryMap().ref().put(p1, p2.isUnknown() ? p2 : encodeQuery(p2)); + getQueryMap().ref().put(p1, p2.isUnknown() ? new longchar() : new longchar(encodeQuery(p2))); })); } === modified file 'src/com/goldencode/p2j/oo/net/http/AuthenticatedRequest.java' --- src/com/goldencode/p2j/oo/net/http/AuthenticatedRequest.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/AuthenticatedRequest.java 2021-02-23 07:39:32 +0000 @@ -8,6 +8,9 @@ ** 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). +** ME 20210209 Adapted the mambo jambo 4GL code to pass the tests: +** - remove only set the entry as unknown +** - add does some kind of array resize, all unknowns are moved at the end ** CA 20210219 OO input parameter definitions for functions/procedures must not register with ObjectOps ** - TypeFactory.initInput will take care of this. ** 004 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy @@ -82,6 +85,7 @@ import static com.goldencode.p2j.util.BlockManager.returnNormal; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import com.goldencode.p2j.oo.core.Assert; @@ -202,10 +206,34 @@ listeners = new ArrayList>(); } - if (!listeners.contains(poListener)) - { + if (!listeners.stream().filter(l -> poListener.ref().legacyEquals(l).booleanValue()).findFirst().isPresent()) + { + // 4GL mambo jambo, some sort of array resize + int prevSize = listeners.size(); + int idx = 0; + + for (int i = 0; i < prevSize; i++) + { + if (!listeners.get(idx)._isValid()) + { + listeners.remove(idx); + } + else + { + idx++; + } + } + + ObjectOps.increment(poListener.ref()); listeners.add(poListener); - } + + idx = prevSize + 1 - listeners.size(); + + for (int i = 0; i < idx; i++) + { + listeners.add(TypeFactory.object(IauthFilterEventHandler.class)); + } + } })); } @@ -225,7 +253,19 @@ internalProcedure(AuthenticatedRequest.class, this, "RemoveAuthenticationCallback", new Block((Body) () -> { if (poListener._isValid() && listeners != null) { - listeners.remove(poListener); + // TODO: 4GL quirk - just leaves the previous entry only set as null + // listeners.remove(poListener); + Iterator> it = listeners.iterator(); + + while (it.hasNext()) + { + object listener = it.next(); + + if (listener.ref().legacyEquals(poListener).booleanValue()) + { + listener.setUnknown(); + } + } } })); } === modified file 'src/com/goldencode/p2j/oo/net/http/HttpHeaderBuilder.java' --- src/com/goldencode/p2j/oo/net/http/HttpHeaderBuilder.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/HttpHeaderBuilder.java 2021-02-23 07:39:32 +0000 @@ -119,9 +119,7 @@ @Override protected object initialValue() { - object registry = - TypeFactory.object(BuilderRegistry.class); - return registry; + return TypeFactory.object(BuilderRegistry.class); } }; @@ -203,16 +201,17 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) public static object getRegistry() { - return function(null, "Registry", object.class, new Block((Body) () -> + return function(HttpHeaderBuilder.class, "Registry", object.class, new Block((Body) () -> { - if (REGISTRY.get().isUnknown()) + object registry = REGISTRY.get(); + + if (!registry._isValid()) { - object registry = ObjectOps.newInstance(BuilderRegistry.class, "I", - ObjectOps.getLegacyClass(HttpHeaderBuilder.class)); + registry.assign(ObjectOps.newInstance(BuilderRegistry.class, "I", + ObjectOps.getLegacyClass(HttpHeaderBuilder.class))); initializeRegistry(registry); - REGISTRY.get().assign(registry); } - returnNormal(REGISTRY.get()); + returnNormal(registry); })); } @@ -276,9 +275,8 @@ private static void initializeRegistry(final object _poRegistry) { - internalProcedure(null, "InitializeRegistry", new Block((Body) () -> + internalProcedure(HttpHeaderBuilder.class, "InitializeRegistry", new Block((Body) () -> { - _poRegistry.ref().put(new character("*"), ObjectOps.getLegacyClass(DefaultHeaderBuilder.class)); _poRegistry.ref().put(new character("Content-Disposition"), === modified file 'src/com/goldencode/p2j/oo/net/http/ProxyHttpClient.java' --- src/com/goldencode/p2j/oo/net/http/ProxyHttpClient.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/ProxyHttpClient.java 2021-02-23 07:39:32 +0000 @@ -7,7 +7,8 @@ ** -#- -I- --Date-- ---------------------------------------Description---------------------------------------- ** 001 IAS 20190923 First version. ** 002 ME 20200410 Fully implement ISupportProxy interface. -** 003 MP 20200603 add constructors and methods like originar class. +** 003 MP 20200603 Add constructors and methods like originar class. +** ME 20210210 Implement additional ctor's and execute method. ** CA 20210219 OO input parameter definitions for functions/procedures must not register with ObjectOps ** - TypeFactory.initInput will take care of this. ** CA 20210221 Fixed parameters at the LegacySignature annotation. @@ -82,6 +83,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.lang.LegacyClass; import com.goldencode.p2j.oo.net.Uri; /** @@ -114,7 +117,22 @@ internalProcedure(ProxyHttpClient.class, this, "Execute", new Block((Body) () -> { - UnimplementedFeature.missing("ProxyHttpClient:Execute METHOD"); + object oProxy = TypeFactory.object(ISupportProxy.class); + object proxyCls = ObjectOps.getLegacyClass(ISupportProxy.class); + + if (ObjectOps.typeOf(poRequest, ISupportProxy.class).booleanValue()) + { + oProxy.assign(ObjectOps.cast(poRequest, ISupportProxy.class)); + } + else + { + poRequest.assign(RequestBuilder.decorateRequest(proxyCls, poRequest)); + oProxy.assign(ObjectOps.cast(poRequest, ISupportProxy.class)); + } + + oProxy.ref().setProxyUri(proxyUri); + + super.execute(poRequest, poResponse); })); } @@ -147,8 +165,10 @@ internalProcedure(ProxyHttpClient.class, this, "__net_http_ProxyHttpClient_constructor__", new Block((Body) () -> { - UnimplementedFeature.missing("ProxyHttpClient II CONSTRUCTOR"); - //__net_http_HttpClientDecorator_constructor__(); + __net_http_HttpClientDecorator_constructor__(poClient); + + Assert.notNull(poProxy, new character("Proxy server URI")); + proxyUri.assign(poProxy); })); } === modified file 'src/com/goldencode/p2j/oo/net/http/RequestBuilder.java' --- src/com/goldencode/p2j/oo/net/http/RequestBuilder.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/RequestBuilder.java 2021-02-23 07:39:32 +0000 @@ -11,6 +11,7 @@ ** 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. +** 20210208 Fix static registry property initialization. ** CA 20210221 Fixed parameters at the LegacySignature annotation. ** 007 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. @@ -143,9 +144,7 @@ { protected object initialValue() { - object registry = - TypeFactory.object(BuilderRegistry.class); - return registry; + return TypeFactory.object(BuilderRegistry.class); } }; /** @@ -236,9 +235,9 @@ { return function(null, "Registry", object.class, new Block((Body) () -> { - object registry = RequestBuilder.REGISTRY.get(); + object registry = REGISTRY.get(); - if (!registry.isValid().booleanValue()) { + if (!registry._isValid()) { registry.assign(ObjectOps.newInstance(BuilderRegistry.class)); initializeRegistry(registry); } === modified file 'src/com/goldencode/p2j/oo/net/http/ResponseBuilder.java' --- src/com/goldencode/p2j/oo/net/http/ResponseBuilder.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/ResponseBuilder.java 2021-02-23 07:39:32 +0000 @@ -8,6 +8,7 @@ ** 001 IAS 20190923 First version. ** 002 MP 20200603 Add missing stubs taken by converting the skeleton using FWD. ** 003 ME 20201029 Implement as per OE12.2. +** 20210208 Fix static registry property initialization. ** 004 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -143,8 +144,6 @@ ObjectOps.getLegacyClass(HttpResponse.class)); registry.ref()._put(ObjectOps.getLegacyName(ResponseBuilder.class), ObjectOps.getLegacyClass(DefaultResponseBuilder.class)); - - REGISTRY.set(registry); } returnNormal(registry); === modified file 'src/com/goldencode/p2j/oo/net/http/filter/payload/DefaultRequestFilter.java' --- src/com/goldencode/p2j/oo/net/http/filter/payload/DefaultRequestFilter.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/payload/DefaultRequestFilter.java 2021-02-23 07:39:32 +0000 @@ -7,6 +7,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 +** ME 20210204 Fix writeMessage and extractEntity methods. ** ** 003 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. @@ -164,7 +165,7 @@ { object oByteBucket = TypeFactory.object(ByteBucket.class); - if (poRequest._isValid()) + if (poRequest.ref().getEntity()._isValid()) { oByteBucket.assign(this.extractEntity(poRequest)); } @@ -179,7 +180,7 @@ bucket().putString(new longchar(TextOps.concat(chr(13), chr(10)))); - if (poRequest.ref().getContentLength().intValue() >= 0) + if (poRequest.ref().getContentLength().intValue() > 0) { bucket().putBytes(oByteBucket); } @@ -200,48 +201,40 @@ { object oMessageBody = ByteBucket.instance(); - object oMWB = TypeFactory.object(MessageWriterBuilder.class); - oMWB.assign(BodyWriterBuilder.build_1(_poRequest)); - - object oMWB2 = TypeFactory.object(MessageWriterBuilder.class); - oMWB2.assign(oMWB.ref().writeTo(oMessageBody)); - - object oMW = TypeFactory.object(MessageWriter.class); - oMW.assign(oMWB2.ref().getWriter()); + object oMWB = BodyWriterBuilder.build_1(poRequest); + object oBodyWriter = oMWB.ref().writeTo(oMessageBody).ref().getWriter(); - object oBodyWriter = TypeFactory.object(MessageWriter.class); - oBodyWriter.assign(oMW); - if (!oBodyWriter._isValid()) { - 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)); + character errMsg = TextOps.substitute("Unable to build request for transmission: no builder available for Content-Type: &1", + poRequest.ref().getContentType()); + logger.ref().error(errMsg); + undoThrow(AppError.newInstance(errMsg, new integer(0))); } oBodyWriter.ref().open(); - int64 iBytesWritten = oBodyWriter.ref().write(_poRequest.ref().getEntity()); + int64 iBytesWritten = oBodyWriter.ref().write(poRequest.ref().getEntity()); oBodyWriter.ref().close(); if (ObjectOps.typeOf(oBodyWriter, ISupportEncoding.class).booleanValue()) { object oSuppEnc = ObjectOps.cast(oBodyWriter, ISupportEncoding.class); - _poRequest.ref().setCharacterEncoding(oSuppEnc.ref().getEncoding()); + poRequest.ref().setCharacterEncoding(oSuppEnc.ref().getEncoding()); } if (ObjectOps.typeOf(oBodyWriter, ISupportMultipartEntity.class).booleanValue()) { object oSuppMultiEnt = ObjectOps.cast(oBodyWriter, ISupportMultipartEntity.class); - _poRequest.ref().getHeader(new character("Content-Type")).ref().setParameterValue(new character("boundary"), oSuppMultiEnt.ref().getBoundary()); + poRequest.ref().getHeader(new character("Content-Type")).ref().setParameterValue(new character("boundary"), oSuppMultiEnt.ref().getBoundary()); } if (ObjectOps.typeOf(oBodyWriter, ISupportTransferEncoding.class).booleanValue()) { object oSuppTransfEnc = ObjectOps.cast(oBodyWriter, ISupportTransferEncoding.class); - _poRequest.ref().setTransferEncoding(oSuppTransfEnc.ref().getTransferEncoding()); + poRequest.ref().setTransferEncoding(oSuppTransfEnc.ref().getTransferEncoding()); } - _poRequest.ref().setContentLength(new integer(iBytesWritten)); + poRequest.ref().setContentLength(new integer(iBytesWritten)); oMessageBody.assign(ObjectOps.cast(oBodyWriter.ref().getEntity(), ByteBucket.class)); - _poRequest.ref().setContentMd5(oMessageBody.ref().getHash(HashAlgorithmEnum.md5)); + poRequest.ref().setContentMd5(oMessageBody.ref().getHash(HashAlgorithmEnum.md5)); returnNormal(oMessageBody); })); @@ -335,7 +328,7 @@ bucket().putString(new longchar(cMsg)); } - if (poRequest.ref().getTransferEncoding().getValue() != TransferEncodingEnum.none.ref().toLegacyString().getValue()) + if (!CompareOps._isEqual(poRequest.ref().getTransferEncoding(), TransferEncodingEnum.none.ref().toLegacyString())) { character cMsg = TextOps.concat("Accept-Encoding: ", TextOps.toLowerCase(poRequest.ref().getTransferEncoding()), chr(13), chr(10)); === modified file 'src/com/goldencode/p2j/oo/net/http/filter/payload/FormDataBodyWriter.java' --- src/com/goldencode/p2j/oo/net/http/filter/payload/FormDataBodyWriter.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/payload/FormDataBodyWriter.java 2021-02-23 07:39:32 +0000 @@ -8,7 +8,8 @@ ** 001 IAS 20190923 First version. ** 002 MP 20200709 Complete methods like legacy class ** 003 CA 20210113 Renamed Iiterator.next to Iiterator.next_, to follow NameConverter's rules. -** 004 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy +** 004 ME 20210209 Fix and clean-up write (object) method. +** 005 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -130,9 +131,9 @@ { internalProcedure(this, "Open", new Block((Body) () -> { - if (!entity.isValid().booleanValue()) + if (!entity._isValid()) { - entity.assign(ByteBucket.instance().ref()); + entity.assign(ByteBucket.instance()); } super.open(); })); @@ -181,20 +182,17 @@ object poData = TypeFactory.initInput(_poData); return function(this, "Write", int64.class, new Block((Body) () -> { - int64 bytesWriten = TypeFactory.int64(); - if (!poData._isValid()) { - returnNormal(new int64(0)); + returnNormal(0); } if (ObjectOps.typeOf(poData, IStringStringMap.class).booleanValue()) { - int64 initSize = ObjectOps.cast(getEntity(), ByteBucket.class).ref().getSize(); + long initSize = bucket().getSize().longValue(); object oStrStrMap = ObjectOps.cast(poData, StringStringMap.class); object oIterator = oStrStrMap.ref().getEntrySet().ref().iterator(); - character cDel = TypeFactory.character(""); - character cFormStr = TypeFactory.character(); + String cDel = ""; while (oIterator.ref().hasNext().booleanValue()) { @@ -206,36 +204,24 @@ character cKey = oKey.ref().toLegacyString(); character cVal = oVal.ref().toLegacyString(); - character cInterm = TextOps.substitute("&1=&2", cKey, cVal); - cFormStr.assign(cDel.getValue() + cInterm.getValue()); - cDel.assign("&"); - ObjectOps.cast(getEntity(), ByteBucket.class).ref().putString(new longchar(cFormStr)); + character cEntry = TextOps.substitute("&1&2=&3", cDel, oKey.ref().toLegacyString(), oVal.ref().toLegacyString()); + if (cDel.isEmpty()) + cDel = "&"; + bucket().putString(new longchar(cEntry)); } - int newVal = ObjectOps.cast(getEntity(), ByteBucket.class).ref().getSize().intValue(); - int iRsp = newVal - initSize.intValue(); - - int64 i64Rsp = new int64(iRsp); - - returnNormal(i64Rsp); - } - else if (ObjectOps.typeOf(poData, LegacyString.class).booleanValue()) - { - bytesWriten.assign(write(ObjectOps.cast(poData, LegacyString.class).ref().getValue())); + returnNormal(bucket().getSize().longValue() - initSize); } else if (ObjectOps.typeOf(poData, IlongcharHolder.class).booleanValue()) { - bytesWriten.assign(write(ObjectOps.cast(poData, IlongcharHolder.class).ref().getValue())); + returnNormal(write(ObjectOps.cast(poData, IlongcharHolder.class).ref().getValue())); } else if (ObjectOps.typeOf(poData, IcharacterHolder.class).booleanValue()) { - bytesWriten.assign(write(new longchar(ObjectOps.cast(poData, IcharacterHolder.class).ref().getValue()))); + returnNormal(write(new longchar(ObjectOps.cast(poData, IcharacterHolder.class).ref().getValue()))); } - else - { + unsupported(poData); - } - returnNormal(bytesWriten); })); } } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/payload/HtmlBodyWriter.java' --- src/com/goldencode/p2j/oo/net/http/filter/payload/HtmlBodyWriter.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/payload/HtmlBodyWriter.java 2021-02-23 07:39:32 +0000 @@ -7,6 +7,7 @@ ** -#- -I- --Date-- -------------------------------Description-------------------------------- ** 001 IAS 20190923 First version. ** 002 MP 20200709 Complete methods with code just like legacy class +** ME 20210205 Fix file extension check, clean-up. ** 003 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -136,9 +137,9 @@ { internalProcedure(this, "Open", new Block((Body) () -> { - if (!entity.isValid().booleanValue()) + if (!entity._isValid()) { - entity.assign(ByteBucket.instance().ref()); + entity.assign(ByteBucket.instance()); } super.open(); })); @@ -163,24 +164,18 @@ object poData = TypeFactory.initInput(_poData); return function(this, "Write", int64.class, new Block((Body) () -> { - int64 bytesWriten = TypeFactory.int64(); - if (!poData._isValid()) { returnNormal(new int64(0)); } - if (ObjectOps.typeOf(poData, LegacyString.class).booleanValue()) - { - bytesWriten.assign(write(ObjectOps.cast(poData, LegacyString.class).ref().getValue())); - } - else if (ObjectOps.typeOf(poData, IlongcharHolder.class).booleanValue()) - { - bytesWriten.assign(write(ObjectOps.cast(poData, IlongcharHolder.class).ref().getValue())); + if (ObjectOps.typeOf(poData, IlongcharHolder.class).booleanValue()) + { + returnNormal(write(ObjectOps.cast(poData, IlongcharHolder.class).ref().getValue())); } else if (ObjectOps.typeOf(poData, IcharacterHolder.class).booleanValue()) { - bytesWriten.assign(write(new longchar(ObjectOps.cast(poData, IcharacterHolder.class).ref().getValue()))); + returnNormal(write(new longchar(ObjectOps.cast(poData, IcharacterHolder.class).ref().getValue()))); } else if (ObjectOps.typeOf(poData, FileInputStream.class).booleanValue()) { @@ -189,9 +184,9 @@ String[] fileNameParts = StringUtils.split(fileStr.ref().getFileName().getValue(), "."); String fileExt = fileNameParts[fileNameParts.length - 1]; - if (fileExt == "html" || fileExt == "htm") + if (fileExt.equalsIgnoreCase("html") || fileExt.equalsIgnoreCase("htm")) { - returnNormal(super.writeFileStream(fileStr)); + returnNormal(writeFileStream(fileStr)); } else { @@ -199,11 +194,8 @@ undoThrow(AppError.newInstance(msg, 0)); } } - else - { - unsupported(poData); - } - returnNormal(bytesWriten); + + unsupported(poData); })); } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/payload/JsonBodyWriter.java' --- src/com/goldencode/p2j/oo/net/http/filter/payload/JsonBodyWriter.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/payload/JsonBodyWriter.java 2021-02-23 07:39:32 +0000 @@ -9,7 +9,8 @@ ** 002 MP 20200611 Added missing methods as stubs taken by converting the skeleton using FWD. ** 003 CA 20210113 Renamed Iiterator.next to Iiterator.next_, to follow NameConverter's rules. ** Renamed clear() to clear_(), to follow NameConverter's rules. -** 004 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy +** 004 ME 20210210 Fix/extend implementation as of OE12.2. +** 005 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -89,14 +90,15 @@ import com.goldencode.p2j.oo.common.support.IlongcharHolder; import com.goldencode.p2j.oo.common.support.ImemptrHolder; import com.goldencode.p2j.oo.core.*; -import com.goldencode.p2j.oo.core.collections.IStringKeyedMap; +import com.goldencode.p2j.oo.core.collections.Icollection; import com.goldencode.p2j.oo.core.collections.Iiterator; +import com.goldencode.p2j.oo.core.collections.Imap; import com.goldencode.p2j.oo.core.collections.LegacyMapEntry; import com.goldencode.p2j.oo.io.*; import com.goldencode.p2j.oo.json.objectmodel.*; import com.goldencode.p2j.oo.lang.*; -import com.goldencode.p2j.oo.reflect.DataType; -import com.goldencode.p2j.oo.reflect.Property; +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; @@ -151,10 +153,12 @@ { internalProcedure(this, "Open", new Block((Body) () -> { - if (!entity.isValid().booleanValue()) + if (!entity._isValid()) { - entity.assign(ByteBucket.instance().ref()); + entity.assign(ByteBucket.instance()); } + + super.open(); })); } @@ -162,15 +166,38 @@ { @LegacyParameter(name = "phData", type = "HANDLE", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public int64 write(final handle _phData) { handle phData = TypeFactory.initInput(_phData); + memptr mResult = TypeFactory.memptr(); return function(JsonBodyWriter.class, this, "Write", int64.class, new Block((Body) () -> { - UnimplementedFeature.missing("JsonBodyWriter:Write handle METHOD"); + if (phData._isValid()) + { + if (phData.isType("TEMP-TABLE") || phData.isType("DATASET") || phData.isType("BUFFER")) + { + long now = System.currentTimeMillis(); + phData.unwrapJsonData().writeJson(new TargetData(Serializator.TYPE_MEMPTR, mResult), SessionUtils.isDebugAlert()); + getLogger().ref().trace(TextOps.substitute("WRITE-JSON took &1ms", System.currentTimeMillis() - now)); + bucket().putBytes(mResult); + returnNormal(mResult.length()); + } + else + { + String errMsg = "Unsupported handle type: " + phData.unwrapType().getResourceType().getValue(); + undoThrow(AppError.newInstance(errMsg, 0)); + } + } + else + { + bucket().clear_(); + returnNormal(write(new longchar("null"))); + } + }, (Fini) () -> { + mResult.setLength(0); })); } @@ -189,10 +216,12 @@ @Override public int64 write(longchar _pData) { + longchar pData = TypeFactory.initInput(_pData); + return function(this, "Write", int64.class, new Block((Body) () -> { - bucket().putString(_pData); - returnNormal(new int64(TextOps.byteLength(_pData))); + bucket().putString(pData); + returnNormal(TextOps.byteLength(pData)); })); } @@ -209,12 +238,12 @@ }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override - public int64 write(memptr _pData) + public int64 write(memptr pData) { return function(this, "Write", int64.class, new Block((Body) () -> { - bucket().putBytes(_pData.getPointerValue(), _pData.length()); - returnNormal(_pData.length()); + bucket().putBytes(pData.getPointerValue(), pData.length()); + returnNormal(pData.length()); })); } @@ -222,7 +251,7 @@ { @LegacyParameter(name = "phData", type = "HANDLE", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public int64 writeHandle(final handle _phData) { handle phData = TypeFactory.initInput(_phData); @@ -249,27 +278,18 @@ @Override public int64 write(object poData) { + memptr mptr = TypeFactory.memptr(); + return function(this, "Write", int64.class, new Block((Body) () -> { - longchar lc = TypeFactory.longchar(); - if (!poData._isValid()) { bucket().clear_(); - bucket().putString(new longchar("Null")); - returnNormal(new int64(new longchar("Null").getSize())); - } - else if (ObjectOps.typeOf(poData, LegacyString.class).booleanValue()) - { - object oLegacyString = ObjectOps.cast(poData, LegacyString.class); - returnNormal(write(oLegacyString.ref().getValue())); + returnNormal(write(new longchar("Null"))); } else if (ObjectOps.typeOf(poData, LegacyError.class).booleanValue()) { - object oLegacyError = ObjectOps.cast(poData, LegacyError.class); - object jObjRsp = ObjectOps.newInstance(JsonObject.class); - jObjRsp.assign(this.writeError(oLegacyError)); - returnNormal(this.write(jObjRsp)); + returnNormal(write(this.writeError(ObjectOps.cast(poData, LegacyError.class)))); } else if (ObjectOps.typeOf(poData, IcharacterHolder.class).booleanValue()) { @@ -284,33 +304,17 @@ else if (ObjectOps.typeOf(poData, FileInputStream.class).booleanValue()) { object fis = ObjectOps.cast(poData, FileInputStream.class); - String fn = fis.ref().getFileName().getValue(); - String ext = ""; - int dp = fn.lastIndexOf('.'); - if (dp >=0 ) - { - ext = fn.substring(dp + 1); - } - if ("json".equalsIgnoreCase(ext)) - { - returnNormal(writeFileStream(fis)); - } - String msg = String.format("Unsupported file extension .%s for JSON", ext); + + String[] result = TextOps.splitInt(fis.ref().getFileName().getValue(), '.'); + + if (result[result.length - 1].equalsIgnoreCase("json")) + { + returnNormal(this.writeFileStream(fis)); + } + + String msg = String.format("Unsupported file extension .%s for JSON", result[result.length - 1]); undoThrow(AppError.newInstance(msg, 0)); } - else if (ObjectOps.typeOf(poData, ByteBucket.class).booleanValue()) - { - object mb = ObjectOps.cast(poData, ByteBucket.class); - lc.assign(mb.ref().getString()); - bucket().putString(lc); - returnNormal(new int64(TextOps.lengthOf(lc))); - } - else if (ObjectOps.typeOf(poData, Memptr.class).booleanValue()) - { - object oMemptr = ObjectOps.cast(poData, Memptr.class); - memptr mptr = oMemptr.ref().getValue(); - returnNormal(this.write(mptr)); - } else if (ObjectOps.typeOf(poData, IhandleHolder.class).booleanValue()) { object oHandleHolder = ObjectOps.cast(poData, IhandleHolder.class); @@ -320,51 +324,121 @@ else if (ObjectOps.typeOf(poData, ImemptrHolder.class).booleanValue()) { object oIMemptr = ObjectOps.cast(poData, ImemptrHolder.class); - memptr mptr = oIMemptr.ref().getValue(); + mptr.assign(oIMemptr.ref().getValue()); returnNormal(this.write(mptr)); } - else if (ObjectOps.typeOf(poData, IStringKeyedMap.class).booleanValue()) + else if (ObjectOps.typeOf(poData, Imap.class).booleanValue()) { object oJsonObj = ObjectOps.newInstance(JsonObject.class); - object oStrKeyMap = ObjectOps.cast(poData, IStringKeyedMap.class); - object oIterator = oStrKeyMap.ref().getEntrySet().ref().iterator(); + object oMap = ObjectOps.cast(poData, Imap.class); + object oIterator = oMap.ref().getEntrySet().ref().iterator(); while (oIterator.ref().hasNext().booleanValue()) { object oMapEntry = ObjectOps.cast(oIterator.ref().next_(), LegacyMapEntry.class); - object oKey = ObjectOps.cast(oMapEntry.ref().getKey(), LegacyString.class); + object oKey = oMapEntry.ref().getKey(); object oVal = oMapEntry.ref().getValue(); - character cKey = oKey.ref().toLegacyString(); - character cVal = oVal.ref().toLegacyString(); + // TODO: value should be converted to something more than strings... + if (oKey._isValid()) + { + if (oVal._isValid()) + { + oJsonObj.ref().add(oKey.ref().toLegacyString(), oVal.ref().toLegacyString()); + } + else + { + oJsonObj.ref().addNull(oKey.ref().toLegacyString()); + } + } + } + + returnNormal(this.write(oJsonObj)); + } + else if (ObjectOps.typeOf(poData, Icollection.class).booleanValue()) + { + object oJson = ObjectOps.newInstance(JsonArray.class); + object oCol = ObjectOps.cast(poData, Icollection.class); + object oIterator = oCol.ref().iterator(); + + while (oIterator.ref().hasNext().booleanValue()) + { + object item = oIterator.ref().next_(); - oJsonObj.ref().add(cKey, cVal); + if (item._isValid()) + { + oJson.ref().add(item.ref().toLegacyString()); + } + else + { + oJson.ref().addNull(); + } } - returnNormal(this.write(oJsonObj)); + returnNormal(this.write(oJson)); } else if (ObjectOps.typeOf(poData, JsonConstruct.class).booleanValue()) { object oJsonConstr = ObjectOps.cast(poData, JsonConstruct.class); - memptr mptr = TypeFactory.memptr(); - oJsonConstr.ref().write(mptr, SessionUtils.isDebugAlert()); - int64 len = mptr.length(); - bucket().putBytes(mptr); - mptr.setLength(0L); - returnNormal(new int64(len)); + + oJsonConstr.ref().write(mptr); + returnNormal(write(mptr)); } else { - String msg = String.format("Unsupported object type: %s", poData.ref().getClass().getTypeName()); + String msg = String.format("JsonBodyWriter cannot convert object type %s to JSON", + poData.ref().getLegacyClass().ref().getTypeName().toStringMessage()); undoThrow(AppError.newInstance(msg, 0)); } - returnNormal(new int64(0)); + }, (Fini) () -> { + mptr.setLength(0); })); } /** + * Write data to/from the object array + * + * @param poData data to be written + * + * @return number of bytes written + */ + @LegacySignature(returns = "INT64", type = Type.METHOD, name = "Write", parameters = + { + @LegacyParameter(name = "poData", type = "OBJECT", + qualified = "progress.lang.object", extent = -1, mode = "INPUT") + }) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) + public int64 write(object[] poData) + { + return function(this, "Write", int64.class, new Block((Body) () -> { + if (poData.length == 0) + { + returnNormal(write(new object())); + } + else + { + object oJson = ObjectOps.newInstance(JsonArray.class); + + for (int i = 0; i < poData.length; i++) + { + if (poData[i]._isValid()) + { + oJson.ref().add(poData[i].ref().toLegacyString()); + } + else + { + oJson.ref().addNull(); + } + } + + returnNormal(write(oJson)); + } + })); + } + + /** * Write error. * * @param error error to be written. @@ -377,14 +451,10 @@ object oError = TypeFactory.object(JsonObject.class); object oErrorList = TypeFactory.object(JsonArray.class); integer iLoop = TypeFactory.integer(); - integer iMax = TypeFactory.integer(); - object oProp = TypeFactory.object(Property.class); - object oInner = TypeFactory.object(LegacyError.class); Assert.notNull(poError, new character("Error")); oResponse.assign(ObjectOps.newInstance(JsonObject.class)); oErrorList.assign(ObjectOps.newInstance(JsonArray.class)); - iMax.assign(poError.ref().getNumMessages()); if ((ObjectOps.typeOf(poError, AppError.class)).booleanValue()) { @@ -393,8 +463,10 @@ oResponse.ref().add(new character("_errors"), oErrorList); - for (iLoop.assign(1); _isLessThanOrEqual(iLoop, iMax); iLoop.increment()) + for (int i = 0; i < _poError.ref().getNumMessages().intValue(); i++) { + iLoop.assign(i + 1); + oError.assign(ObjectOps.newInstance(JsonObject.class)); oErrorList.ref().add_2(oError); oError.ref().add(new character("_errorMsg"), poError.ref().getMessage(iLoop)); @@ -404,32 +476,35 @@ if ((SessionUtils.isDebugAlert()).booleanValue()) { oResponse.ref().add(new character("_type"), poError.ref().getLegacyClass().ref().getTypeName()); - } - if (_not(isUnknown(poError.ref().getCallStack()))) + if (!poError.ref().getCallStack().isUnknown()) { oErrorList.assign(ObjectOps.newInstance(JsonArray.class)); - iMax = TextOps.numEntries(poError.ref().getCallStack(), new character(StringUtils.LF)); oResponse.ref().add(new character("_stack"), oErrorList); - for (iLoop.assign(1); _isLessThanOrEqual(iLoop, iMax); iLoop.increment()) + String[] callStack = TextOps.entries(poError.ref().getCallStack().getValue(), "\\n"); + + for (int i = 0; i < callStack.length; i++) { - oErrorList.ref().add(TextOps.entry(iLoop, poError.ref().getCallStack(), new character(StringUtils.LF))); + oErrorList.ref().add(new character(callStack[i])); + } } } - oProp.assign(poError.ref().getLegacyClass().ref().getProperty(new character("InnerError"))); - - if (_and(and(oProp.isValid(), () -> isEqual(oProp.ref().getDataType(), DataType.object_)), () -> LegacyClass.getLegacyClass(oProp.ref().getDataTypeName()).ref().isA(ObjectOps.getLegacyClass(LegacyError.class)))) - { - oInner.assign(oProp.ref().get(poError)); - - if ((oInner.isValid()).booleanValue()) - { - this.writeError(oInner); - } - } +// TODO: accessing any method in LegacyClass throws NPE +// ProcedureManager.CalleeInfoImpl.push #5351 +// oProp.assign(poError.ref().getLegacyClass().ref().getProperty(new character("InnerError"))); +// +// if (_and(and(oProp.isValid(), () -> isEqual(oProp.ref().getDataType(), DataType.object_)), () -> LegacyClass.getLegacyClass(oProp.ref().getDataTypeName()).ref().isA(ObjectOps.getLegacyClass(LegacyError.class)))) +// { +// oInner.assign(oProp.ref().get(poError)); +// +// if ((oInner.isValid()).booleanValue()) +// { +// this.writeError(oInner); +// } +// } return oResponse; }; === modified file 'src/com/goldencode/p2j/oo/net/http/filter/payload/MessageWriter.java' --- src/com/goldencode/p2j/oo/net/http/filter/payload/MessageWriter.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/payload/MessageWriter.java 2021-02-23 07:39:32 +0000 @@ -10,6 +10,7 @@ ** 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. +** 20210204 Allocate memory when reading from file input stream. ** 004 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -483,6 +484,8 @@ return function(this, "WriteFileStream", int64.class, new Block((Body)() -> { Assert.notNull(pStream, new character("File input stream")); + FileSystemOps.initFileInfo(pStream.ref().getFileName()); + mPtr.setLength(FileSystemOps.fileInfoGetSize()); pStream.ref().read(mPtr); === modified file 'src/com/goldencode/p2j/oo/net/http/filter/payload/XmlBodyWriter.java' --- src/com/goldencode/p2j/oo/net/http/filter/payload/XmlBodyWriter.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/payload/XmlBodyWriter.java 2021-02-23 07:39:32 +0000 @@ -10,6 +10,7 @@ ** 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. +** 20210204 Implement missing methods, fix write handle/object. ** 005 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -75,8 +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.util.BlockManager.undoThrowTopLevel; +import static com.goldencode.p2j.util.BlockManager.undoThrow; +import com.goldencode.p2j.oo.common.support.IcharacterHolder; +import com.goldencode.p2j.oo.common.support.IlongcharHolder; import com.goldencode.p2j.oo.common.support.ImemptrHolder; import com.goldencode.p2j.oo.core.*; import com.goldencode.p2j.oo.io.FileInputStream; @@ -179,10 +182,12 @@ { internalProcedure(this, "Open", new Block((Body) () -> { - if (!entity.isValid().booleanValue()) + if (!entity._isValid()) { entity.assign(ByteBucket.instance()); } + + super.open(); })); } @@ -206,26 +211,15 @@ 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 if (pData.isType("TEMP-TABLE") || pData.isType("DATASET") || pData.isType("BUFFER")) + { + pData.unwrapXmlData().writeXml(new TargetData(Serializator.TYPE_MEMPTR, mResult), SessionUtils.isDebugAlert()); + encoding.assign("utf-8"); + } else { String errMsg = "Unsupported handle type: " + pData.unwrapType().getResourceType().getValue(); - undoThrowTopLevel(AppError.newInstance(errMsg, 0)); + undoThrow(AppError.newInstance(errMsg, 0)); } } try @@ -245,7 +239,7 @@ { @LegacyParameter(name = "pData", type = "LONGCHAR", mode = "INPUT") }) - @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_STUB) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) @Override public int64 write(final longchar _pData) { @@ -253,7 +247,20 @@ return function(XmlBodyWriter.class, this, "Write", int64.class, new Block((Body) () -> { - UnimplementedFeature.missing("XmlBodyWriter:Write lc METHOD"); + Assert.notNull(pData, new character("XML data")); + + longchar mContent = TypeFactory.initInput(TextOps.trim(pData)); + + if ( !TextOps.begins(mContent, "<").booleanValue() ) + { + String errMsg = "Character data does not appear to be XML; starts with \"" + + TextOps.substring(mContent, 1, 1).getValue() + "\""; + undoThrow(AppError.newInstance(errMsg, 0)); + } + + encoding.assign(ConvCp.toMime(pData.getCodePage())); + bucket().putString(pData); + returnNormal(TextOps.byteLengthOf(pData)); })); } @@ -290,19 +297,12 @@ { String errMsg = "Data does not appear to be XML; starts with \"" + TextOps.substring(mContent, 1, 10).getValue() + "\""; - undoThrowTopLevel(AppError.newInstance(errMsg, 0)); + undoThrow(AppError.newInstance(errMsg, 0)); } - try - { encoding.assign(ConvCp.toMime(I18nOps.getCPInternal())); bucket().putBytes(pData.getPointerValue(), pData.length()); returnNormal(pData.length()); - } - finally - { - pData.setLength(0); - } })); } @@ -324,18 +324,17 @@ 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, IlongcharHolder.class).booleanValue()) + { + returnNormal(this.write(ObjectOps.cast(poData, IlongcharHolder.class).ref().getValue())); + } + else if (ObjectOps.typeOf(poData, IcharacterHolder.class).booleanValue()) + { + returnNormal(this.write(new longchar(ObjectOps.cast(poData, IcharacterHolder.class).ref().getValue()))); } else if (ObjectOps.typeOf(poData, ImemptrHolder.class).booleanValue()) { @@ -343,9 +342,7 @@ } else if (ObjectOps.typeOf(poData, FileInputStream.class).booleanValue()) { - object oFis = ObjectOps.newInstance(FileInputStream.class); - - oFis.assign(ObjectOps.cast(poData, FileInputStream.class)); + object oFis = ObjectOps.cast(poData, FileInputStream.class); String[] result = TextOps.splitInt(oFis.ref().getFileName().getValue(), '.'); @@ -354,23 +351,11 @@ returnNormal(this.writeFileStream(oFis)); } String errMsg = "Unsupported file extension ." + result[result.length - 1] + " for XML"; - undoThrowTopLevel(AppError.newInstance(errMsg, 0)); + undoThrow(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); - } + + unsupported(poData); })); } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/writer/AuthenticationRequestWriterBuilder.java' --- src/com/goldencode/p2j/oo/net/http/filter/writer/AuthenticationRequestWriterBuilder.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/writer/AuthenticationRequestWriterBuilder.java 2021-02-23 07:39:32 +0000 @@ -9,6 +9,7 @@ ** 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. +** 20210208 Fix static registry property initialization. ** 005 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -222,8 +223,6 @@ 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/BodyWriterRegistry.java' --- src/com/goldencode/p2j/oo/net/http/filter/writer/BodyWriterRegistry.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/writer/BodyWriterRegistry.java 2021-02-23 07:39:32 +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 20201218 Implement as of OE12.2. +** ME 20210208 Fix static registry property initialization. ** 004 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -97,15 +98,7 @@ @Override protected object initialValue() { - object registry = - UndoableFactory.object(BuilderRegistry.class); - - registry.assign(ObjectOps.newInstance(BuilderRegistry.class, "I", - ObjectOps.getLegacyClass(MessageWriter.class))); - - initializeRegistry(registry); - - return registry; + return TypeFactory.object(BuilderRegistry.class); } }; @@ -118,11 +111,19 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static object getRegistry() { - ObjectOps.load(BodyWriterRegistry.class); - return function(BodyWriterRegistry.class, "Registry", object.class, new Block((Body) () -> { - returnNormal(REGISTRY.get()); + object registry = REGISTRY.get(); + + if (!registry._isValid()) + { + registry.assign(ObjectOps.newInstance(BuilderRegistry.class, "I", + ObjectOps.getLegacyClass(MessageWriter.class))); + + initializeRegistry(registry); + } + + returnNormal(registry); })); } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/writer/DefaultMessageWriterBuilder.java' --- src/com/goldencode/p2j/oo/net/http/filter/writer/DefaultMessageWriterBuilder.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/writer/DefaultMessageWriterBuilder.java 2021-02-23 07:39:32 +0000 @@ -10,6 +10,7 @@ ** 003 ME 20200413 Use the ISupportEncoding interface from Net package. ** 004 MP 20201218 Implement as of OE12.2. ** 20210104 clean code of unused assert +** ME 20210204 Cleanup/fix errors on getWritter method. ** 005 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -150,19 +151,18 @@ 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()) + if (!writerType._isValid()) { returnNormal(writer); } writer.assign(ObjectOps.newDynamicInstance(writerType.ref().getTypeName())); - if (hasOption(new character("entity")).booleanValue()) + if (_hasOption("entity")) { entity.assign(ObjectOps.dynamicCast( getOptionObjectValue(new character("entity")), @@ -170,7 +170,7 @@ ))); writer.ref().setEntity(entity); } - if (hasOption(new character("encodedAs")).booleanValue() && + if (_hasOption("encodedAs") && ObjectOps.typeOf(writer, ISupportEncoding.class).booleanValue()) { ObjectOps.cast(writer, ISupportEncoding.class).ref().setEncoding( === modified file 'src/com/goldencode/p2j/oo/net/http/filter/writer/EntityWriterRegistry.java' --- src/com/goldencode/p2j/oo/net/http/filter/writer/EntityWriterRegistry.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/writer/EntityWriterRegistry.java 2021-02-23 07:39:32 +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 20201218 Implement as of OE12.2. +** ME 20210208 Fix static registry property initialization. ** 004 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -100,11 +101,7 @@ @Override protected object initialValue() { - object registry = - UndoableFactory.object(BuilderRegistry.class); - registry.assign(ObjectOps.newInstance(BuilderRegistry.class, "I", ObjectOps.getLegacyClass(MessageWriter.class))); - initializeRegistry(registry); - return registry; + return TypeFactory.object(BuilderRegistry.class); } }; @@ -117,11 +114,18 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static object getRegistry() { - ObjectOps.load(BodyWriterRegistry.class); - - return function(BodyWriterRegistry.class, "Registry", object.class, new Block((Body) () -> + return function(EntityWriterRegistry.class, "Registry", object.class, new Block((Body) () -> { - returnNormal(REGISTRY.get()); + object registry = EntityWriterRegistry.REGISTRY.get(); + + if (!registry._isValid()) + { + registry.assign(ObjectOps.newInstance(BuilderRegistry.class, "I", + ObjectOps.getLegacyClass(MessageWriter.class))); + initializeRegistry(registry); + } + + returnNormal(registry); })); } @@ -139,7 +143,7 @@ public static void initializeRegistry(final object _poRegistry) { - internalProcedure(null, "InitializeRegistry", new Block((Body) ()-> { + internalProcedure(EntityWriterRegistry.class, "InitializeRegistry", new Block((Body) ()-> { object handlerCls = ObjectOps.getLegacyClass(BinaryEntityWriter.class); // binary _poRegistry.ref()._put("application/gzip", handlerCls); === modified file 'src/com/goldencode/p2j/oo/net/http/filter/writer/MessageWriterBuilder.java' --- src/com/goldencode/p2j/oo/net/http/filter/writer/MessageWriterBuilder.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/writer/MessageWriterBuilder.java 2021-02-23 07:39:32 +0000 @@ -9,7 +9,7 @@ ** 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. -** +** 20210208 Fix static registry property initialization. ** 004 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -109,12 +109,7 @@ @Override protected object initialValue() { - object registry = - TypeFactory.object(BuilderRegistry.class); - - registry.assign(ObjectOps.newInstance(BuilderRegistry.class, "I", ObjectOps.getLegacyClass(MessageWriterBuilder.class))); - initializeRegistry(registry); - return registry; + return TypeFactory.object(BuilderRegistry.class); } }; @@ -190,7 +185,16 @@ { return function(BodyWriterRegistry.class, "Registry", object.class, new Block((Body) () -> { - returnNormal(REGISTRY.get()); + object registry = EntityWriterRegistry.REGISTRY.get(); + + if (!registry._isValid()) + { + registry.assign(ObjectOps.newInstance(BuilderRegistry.class, "I", + ObjectOps.getLegacyClass(MessageWriter.class))); + initializeRegistry(registry); + } + + returnNormal(registry); })); } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/writer/RequestWriterBuilder.java' --- src/com/goldencode/p2j/oo/net/http/filter/writer/RequestWriterBuilder.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/writer/RequestWriterBuilder.java 2021-02-23 07:39:32 +0000 @@ -7,6 +7,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 +** ME 20210208 Fix static registry property initialization. ** CA 20210219 OO input parameter definitions for functions/procedures must not register with ObjectOps ** - TypeFactory.initInput will take care of this. ** 003 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy @@ -118,13 +119,7 @@ @Override protected object initialValue() { - object registry = - UndoableFactory.object(BuilderRegistry.class); - - registry.assign(ObjectOps.newInstance(BuilderRegistry.class, "I", - ObjectOps.getLegacyClass(MessageWriter.class))); - initializeRegistry(registry); - return registry; + return TypeFactory.object(BuilderRegistry.class); } }; @@ -181,11 +176,18 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static object getRegistry() { - ObjectOps.load(RequestWriterBuilder.class); - return function(null, "Registry", object.class, new Block((Body) () -> { - returnNormal(REGISTRY.get()); + object registry = EntityWriterRegistry.REGISTRY.get(); + + if (!registry._isValid()) + { + registry.assign(ObjectOps.newInstance(BuilderRegistry.class, "I", + ObjectOps.getLegacyClass(MessageWriter.class))); + initializeRegistry(registry); + } + + returnNormal(registry); })); } === modified file 'src/com/goldencode/p2j/oo/net/http/filter/writer/SetHeaderMessageWriterBuilder.java' --- src/com/goldencode/p2j/oo/net/http/filter/writer/SetHeaderMessageWriterBuilder.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/filter/writer/SetHeaderMessageWriterBuilder.java 2021-02-23 07:39:32 +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 ME 20200930 Fix constructor by sending the message as input to the writer. +** 20210208 Fix static registry property initialization, add static ctor. ** 004 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -67,9 +68,11 @@ package com.goldencode.p2j.oo.net.http.filter.writer; +import static com.goldencode.p2j.util.BlockManager.externalProcedure; 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.util.BlockManager.onBlockLevel; import static com.goldencode.p2j.util.BlockManager.returnNormal; import com.goldencode.p2j.oo.core.*; @@ -78,6 +81,8 @@ import com.goldencode.p2j.oo.net.http.filter.header.*; 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.*; /** @@ -101,15 +106,20 @@ @Override protected object initialValue() { - object registry = - TypeFactory.object(BuilderRegistry.class); - registry.assign(ObjectOps.newInstance(BuilderRegistry.class, "I", - ObjectOps.getLegacyClass(IHttpMessageWriter.class))); - initializeRegistry(registry); - return registry; + return TypeFactory.object(BuilderRegistry.class); } }; + @LegacySignature(type = Type.CONSTRUCTOR) + @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL) + public static void __net_http_filter_writer_SetHeaderMessageWriterBuilder_constructor__static__() + { + externalProcedure(SetHeaderMessageWriterBuilder.class, new Block((Body) () -> + { + onBlockLevel(Condition.ERROR, Action.THROW); + })); + } + /** * Get registry. * @@ -119,27 +129,24 @@ @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static object getRegistry() { - return function(null, "Registry", object.class, new Block((Body) () -> + return function(SetHeaderMessageWriterBuilder.class, "Registry", object.class, new Block((Body) () -> { - returnNormal(REGISTRY.get()); + object registry = REGISTRY.get(); + + if (!registry._isValid()) + { + registry.assign(ObjectOps.newInstance(BuilderRegistry.class, "I", + ObjectOps.getLegacyClass(IHttpMessageWriter.class))); + initializeRegistry(registry); + } + + returnNormal(registry); })); } - /** - * 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) ()-> { + private static void initializeRegistry(final object _poRegistry) + { + internalProcedure(SetHeaderMessageWriterBuilder.class, "InitializeRegistry", new Block((Body) ()-> { _poRegistry.ref().put(new character("Accept-Encoding"), ObjectOps.getLegacyClass(TransferEncodingSetHeaderFilter.class)); _poRegistry.ref().put(new character("Set-Cookie"), @@ -166,10 +173,13 @@ }) @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL) public static object build( - object poMessage, - object poHeader) + object _poMessage, + object _poHeader) { - return function(null, "Build", object.class, new Block((Body)() -> { + object poMessage = TypeFactory.initInput(_poMessage); + object poHeader = TypeFactory.initInput(_poHeader); + + return function(SetHeaderMessageWriterBuilder.class, "Build", object.class, new Block((Body)() -> { object writer = TypeFactory.object(IHttpMessageWriter.class); object writerType = TypeFactory.object(LegacyClass.class); @@ -177,8 +187,9 @@ Assert.notNull(poMessage, new character("Message")); Assert.notNull(poHeader, new character("Header")); - writerType.assign(REGISTRY.get().ref().get(poHeader.ref().getName())); - if (!writerType.isValid().booleanValue()) + writerType.assign(getRegistry().ref().get(poHeader.ref().getName())); + + if (!writerType._isValid()) { returnNormal(writer); } === modified file 'src/com/goldencode/p2j/oo/net/http/lib/ClientLibraryBuilder.java' --- src/com/goldencode/p2j/oo/net/http/lib/ClientLibraryBuilder.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/lib/ClientLibraryBuilder.java 2021-02-23 07:39:32 +0000 @@ -11,6 +11,8 @@ ** 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 +** ME 20210208 Fix static registry property initialization. +** 20210210 Lazy instantiate registry, the object seems to be deleted otherwise. ** 007 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy ** signature. */ @@ -121,11 +123,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); } }; @@ -192,7 +190,14 @@ { return function(null, "Registry", object.class, new Block((Body) () -> { - returnNormal(ClientLibraryBuilder.REGISTRY.get()); + object registry = REGISTRY.get(); + + if (!registry._isValid()) + { + registry.assign(ObjectOps.newInstance(BuilderRegistry.class)); + initializeRegistry(registry); + } + returnNormal(registry); })); } === modified file 'src/com/goldencode/p2j/oo/net/http/lib/sockets/LegacySocketLibrary.java' --- src/com/goldencode/p2j/oo/net/http/lib/sockets/LegacySocketLibrary.java 2021-02-21 16:25:50 +0000 +++ src/com/goldencode/p2j/oo/net/http/lib/sockets/LegacySocketLibrary.java 2021-02-23 07:39:32 +0000 @@ -13,6 +13,7 @@ ** by LegacySocketLibraryBuilder class. ** 006 ME 20210128 Add query parameters and fragment when executing request. ** 20210130 Fix call to 'next' iterator method. +** 20210210 Add support for proxy, use version info from request. ** CA 20210219 OO input parameter definitions for functions/procedures must not register with ObjectOps ** - TypeFactory.initInput will take care of this. ** 007 CA 20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy @@ -647,12 +648,24 @@ requestBuilder.setEntity(httpEntity); } setHeaders(req, requestBuilder); - ProtocolVersion pv = new ProtocolVersion("HTTP", 1, 1); + + String[] ver = req.ref().getVersion().getValue().split("[/.]+"); + int majVer = ver.length > 1 ? Integer.parseInt(ver[1]) : 1; + int minVer = ver.length > 2 ? Integer.parseInt(ver[2]) : 1; + + ProtocolVersion pv = new ProtocolVersion(ver[0], majVer, minVer); requestBuilder.setVersion(pv); HttpUriRequest request = requestBuilder.build(); - - org.apache.http.client.HttpClient client = createHttpClient(); + + object proxyUri = TypeFactory.object(Uri.class); + + if (ObjectOps.typeOf(req, ISupportProxy.class).booleanValue()) + { + proxyUri.assign(ObjectOps.cast(req, ISupportProxy.class).ref().getProxyURI()); + } + + org.apache.http.client.HttpClient client = createHttpClient(proxyUri); HttpResponse response; try @@ -697,13 +710,13 @@ * * @return Apache HTTPClient */ - private org.apache.http.client.HttpClient createHttpClient() + private org.apache.http.client.HttpClient createHttpClient(object proxyUri) { SSLContext sslContext = SSL_CONTEXT.get(); HttpClientConnectionManager connectionManager = CONNECTION_NANAGER.get(); - return HttpClientBuilder.create(). + HttpClientBuilder builder = HttpClientBuilder.create(). setConnectionManager(connectionManager). // Redirect should be handled by the RequstStatusFilter for all methods setRedirectStrategy(new RedirectStrategy() @@ -724,9 +737,15 @@ } }). setSSLContext(sslContext). - setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build()). - - build(); + setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build()); + + if (proxyUri._isValid()) + { + HttpHost proxy = new HttpHost(proxyUri.ref().getHost().toStringMessage(), proxyUri.ref().getPort().intValue()); + builder.setProxy(proxy); + } + + return builder.build(); } /** # Begin bundle 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 1J0YTB9vE4gf/xdyRThQkOSSTNw=