diff --git a/migration/i8.2/oracle/202104162211_IDEMPIERE-4762.sql b/migration/i8.2/oracle/202104162211_IDEMPIERE-4762.sql
new file mode 100644
index 0000000000..c0e17c5cc5
--- /dev/null
+++ b/migration/i8.2/oracle/202104162211_IDEMPIERE-4762.sql
@@ -0,0 +1,147 @@
+SET SQLBLANKLINES ON
+SET DEFINE OFF
+
+-- IDEMPIERE-4762 Add AD_StorageProvider_ID to AD_Attachment (FHCA-1165)
+-- Apr 16, 2021, 9:52:15 PM CEST
+INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,IsHtml) VALUES (214420,0,'Storage Provider',254,'AD_StorageProvider_ID',22,'N','N','N','N','N',0,'N',19,0,0,'Y',TO_DATE('2021-04-16 21:52:15','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2021-04-16 21:52:15','YYYY-MM-DD HH24:MI:SS'),100,200238,'N','N','D','N','N','N','Y','c6ce4bd2-7688-451c-89bd-ac02866671fb','Y',0,'N','N','N')
+;
+
+-- Apr 16, 2021, 9:53:14 PM CEST
+INSERT INTO AD_Field (AD_Field_ID,Name,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,ColumnSpan) VALUES (206604,'Storage Provider',173,214420,'Y',22,100,'N','N','N','N',0,0,'Y',TO_DATE('2021-04-16 21:53:14','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2021-04-16 21:53:14','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','c1e37d25-d4ed-4681-a102-34be0dc1b5a8','Y',100,2)
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET SeqNo=10, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=960
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET SeqNo=20, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=2039
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET SeqNo=30, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=963
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET IsDisplayed='Y', SeqNo=40, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, XPosition=5, IsToolbarButton=NULL,Updated=TO_DATE('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=964
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET SeqNo=50, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=3819
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET SeqNo=60, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=10074
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET SeqNo=70, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=206604
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET IsDisplayed='Y', SeqNo=80, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, XPosition=5, IsToolbarButton=NULL,Updated=TO_DATE('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=961
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET SeqNo=0, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=204470
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET SeqNo=0, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=959
+;
+
+-- Apr 16, 2021, 9:55:50 PM CEST
+UPDATE AD_Column SET FKConstraintName='ADStorageProvider_ADAttachment', FKConstraintType='N',Updated=TO_DATE('2021-04-16 21:55:50','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=214420
+;
+
+-- Apr 16, 2021, 9:55:50 PM CEST
+ALTER TABLE AD_Attachment ADD AD_StorageProvider_ID NUMBER(10) DEFAULT NULL
+;
+
+-- Apr 16, 2021, 9:55:50 PM CEST
+ALTER TABLE AD_Attachment ADD CONSTRAINT ADStorageProvider_ADAttachment FOREIGN KEY (AD_StorageProvider_ID) REFERENCES ad_storageprovider(ad_storageprovider_id) DEFERRABLE INITIALLY DEFERRED
+;
+
+-- Apr 16, 2021, 11:17:37 PM CEST
+INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,IsHtml) VALUES (214421,0,'Storage Provider',461,'AD_StorageProvider_ID',22,'N','N','N','N','N',0,'N',19,0,0,'Y',TO_DATE('2021-04-16 23:17:37','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2021-04-16 23:17:37','YYYY-MM-DD HH24:MI:SS'),100,200238,'N','N','D','N','N','N','Y','ffac0527-d6d3-4a92-84cb-c15f7ac076c5','Y',0,'N','N','N')
+;
+
+-- Apr 16, 2021, 11:17:39 PM CEST
+UPDATE AD_Column SET FKConstraintName='ADStorageProvider_ADImage', FKConstraintType='N',Updated=TO_DATE('2021-04-16 23:17:39','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=214421
+;
+
+-- Apr 16, 2021, 11:17:39 PM CEST
+ALTER TABLE AD_Image ADD AD_StorageProvider_ID NUMBER(10) DEFAULT NULL
+;
+
+-- Apr 16, 2021, 11:17:39 PM CEST
+ALTER TABLE AD_Image ADD CONSTRAINT ADStorageProvider_ADImage FOREIGN KEY (AD_StorageProvider_ID) REFERENCES ad_storageprovider(ad_storageprovider_id) DEFERRABLE INITIALLY DEFERRED
+;
+
+-- Apr 16, 2021, 11:18:35 PM CEST
+INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,FKConstraintType,IsHtml) VALUES (214422,0,'Storage Provider',754,'AD_StorageProvider_ID',22,'N','N','N','N','N',0,'N',19,0,0,'Y',TO_DATE('2021-04-16 23:18:34','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2021-04-16 23:18:34','YYYY-MM-DD HH24:MI:SS'),100,200238,'N','N','D','N','N','N','Y','d15193c9-69cb-48de-94b4-5afeb82f405a','Y',0,'N','N','N','N')
+;
+
+-- Apr 16, 2021, 11:18:37 PM CEST
+UPDATE AD_Column SET FKConstraintName='ADStorageProvider_ADArchive', FKConstraintType='N',Updated=TO_DATE('2021-04-16 23:18:37','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=214422
+;
+
+-- Apr 16, 2021, 11:18:37 PM CEST
+ALTER TABLE AD_Archive ADD AD_StorageProvider_ID NUMBER(10) DEFAULT NULL
+;
+
+-- Apr 16, 2021, 11:18:37 PM CEST
+ALTER TABLE AD_Archive ADD CONSTRAINT ADStorageProvider_ADArchive FOREIGN KEY (AD_StorageProvider_ID) REFERENCES ad_storageprovider(ad_storageprovider_id) DEFERRABLE INITIALLY DEFERRED
+;
+
+-- Apr 21, 2021, 5:36:53 PM CEST
+UPDATE AD_Process_Para SET SeqNo=90,Updated=TO_DATE('2021-04-21 17:36:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200293
+;
+
+-- Apr 21, 2021, 5:37:39 PM CEST
+UPDATE AD_Process_Para SET DefaultValue='Y',Updated=TO_DATE('2021-04-21 17:37:39','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200290
+;
+
+-- Apr 21, 2021, 5:37:43 PM CEST
+UPDATE AD_Process_Para SET DefaultValue='Y',Updated=TO_DATE('2021-04-21 17:37:43','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200291
+;
+
+-- Apr 21, 2021, 5:37:46 PM CEST
+UPDATE AD_Process_Para SET DefaultValue='Y',Updated=TO_DATE('2021-04-21 17:37:46','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200292
+;
+
+-- Apr 21, 2021, 5:39:08 PM CEST
+INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,Help,PrintName,EntityType,AD_Element_UU) VALUES (203483,0,0,'Y',TO_DATE('2021-04-21 17:38:43','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2021-04-21 17:38:43','YYYY-MM-DD HH24:MI:SS'),100,'IsMigrateData','Migrate Data',NULL,NULL,'Migrate Data','D','cc8e6b76-fd73-4309-8fc6-2d9ead66d39d')
+;
+
+-- Apr 21, 2021, 5:39:16 PM CEST
+INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,DefaultValue,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted,IsAutocomplete) VALUES (200340,0,0,'Y',TO_DATE('2021-04-21 17:39:15','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2021-04-21 17:39:15','YYYY-MM-DD HH24:MI:SS'),100,'Migrate Data',200117,70,20,'N',1,'Y','Y','IsMigrateData','Y','D',203483,'c060a763-cdf5-4b44-9486-5be5fb523674','N','N')
+;
+
+-- Apr 21, 2021, 5:42:35 PM CEST
+INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,Help,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted,MandatoryLogic,IsAutocomplete) VALUES (200341,0,0,'Y',TO_DATE('2021-04-21 17:42:35','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2021-04-21 17:42:35','YYYY-MM-DD HH24:MI:SS'),100,'Record ID','Direct internal record ID','The Record ID is the internal unique identifier of a record. Please note that zooming to the record may not be successful for Orders, Invoices and Shipment/Receipts as sometimes the Sales Order type is not known.',200117,80,11,'Y',22,'N','Record_ID','Y','D',538,'c65e1cd9-1c1b-450c-a789-58feb9b7afe0','N',NULL,'N')
+;
+
+-- Apr 21, 2021, 5:54:28 PM CEST
+UPDATE AD_Process SET Help='
WARNING: This process can be destructive, so please be sure that you have a backup of the database, as well as a backup of your old storage provider.
+
+The process migrates files between storage providers.
+
+- Client: Optional, select a client to migrate, when empty it will migrate all clients with the Actual Storage Provider
- Actual Storage Provider: Alternatively, you can define here the storage provider to migrate
- Storage Provider: The new storage provider to migrate the files
- Migrate Attachment: Migrate the attachment files
- Migrate Archive: Migate the archive files
- Migrate Image: Migrate the image files
- Migrate Data: When unchecked, just the storage provider is changed in client, but the files are not migrated (they can be migrated in a future execution of this same process)
- Record ID Range: Optionally you can define a range of IDs for the records to migrate, so you can run this process in parallel to migrate the data
- Delete old/existing files: If enabled, when a file is migrated the program tries to free space deleting the file from the previous storage provider. Note that migrating from/to a DB storage provider is a destructive action that cannot be recovered, it implies deleting the old/existing files.
+
+In case of failure or timeout, the process can be launched again, it commits on every file migrated.
',Updated=TO_DATE('2021-04-21 17:54:28','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_ID=200117
+;
+
+-- set providers with actual values from client
+UPDATE ad_attachment a SET ad_storageprovider_id = (SELECT ci.ad_storageprovider_id FROM ad_clientinfo ci WHERE ci.ad_client_id=a.ad_client_id)
+WHERE a.ad_client_id IN (SELECT ad_client_id FROM ad_clientinfo WHERE ad_storageprovider_id IS NOT NULL);
+
+UPDATE ad_image i SET ad_storageprovider_id = (SELECT ci.storageimage_id FROM ad_clientinfo ci WHERE ci.ad_client_id=i.ad_client_id)
+WHERE ad_client_id IN (SELECT ad_client_id FROM ad_clientinfo WHERE storageimage_id IS NOT NULL);
+
+UPDATE ad_archive a SET ad_storageprovider_id = (SELECT ci.storagearchive_id FROM ad_clientinfo ci WHERE ci.ad_client_id=a.ad_client_id)
+WHERE ad_client_id IN (SELECT ad_client_id FROM ad_clientinfo WHERE storagearchive_id IS NOT NULL);
+
+SELECT register_migration_script('202104162211_IDEMPIERE-4762.sql') FROM dual
+;
+
diff --git a/migration/i8.2/postgresql/202104162211_IDEMPIERE-4762.sql b/migration/i8.2/postgresql/202104162211_IDEMPIERE-4762.sql
new file mode 100644
index 0000000000..90f00082e2
--- /dev/null
+++ b/migration/i8.2/postgresql/202104162211_IDEMPIERE-4762.sql
@@ -0,0 +1,144 @@
+-- IDEMPIERE-4762 Add AD_StorageProvider_ID to AD_Attachment (FHCA-1165)
+-- Apr 16, 2021, 9:52:15 PM CEST
+INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,IsHtml) VALUES (214420,0,'Storage Provider',254,'AD_StorageProvider_ID',22,'N','N','N','N','N',0,'N',19,0,0,'Y',TO_TIMESTAMP('2021-04-16 21:52:15','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2021-04-16 21:52:15','YYYY-MM-DD HH24:MI:SS'),100,200238,'N','N','D','N','N','N','Y','c6ce4bd2-7688-451c-89bd-ac02866671fb','Y',0,'N','N','N')
+;
+
+-- Apr 16, 2021, 9:53:14 PM CEST
+INSERT INTO AD_Field (AD_Field_ID,Name,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,ColumnSpan) VALUES (206604,'Storage Provider',173,214420,'Y',22,100,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2021-04-16 21:53:14','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2021-04-16 21:53:14','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','c1e37d25-d4ed-4681-a102-34be0dc1b5a8','Y',100,2)
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET SeqNo=10, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=960
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET SeqNo=20, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=2039
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET SeqNo=30, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=963
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET IsDisplayed='Y', SeqNo=40, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, XPosition=5, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=964
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET SeqNo=50, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=3819
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET SeqNo=60, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=10074
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET SeqNo=70, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=206604
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET IsDisplayed='Y', SeqNo=80, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, XPosition=5, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=961
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET SeqNo=0, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=204470
+;
+
+-- Apr 16, 2021, 9:53:53 PM CEST
+UPDATE AD_Field SET SeqNo=0, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2021-04-16 21:53:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=959
+;
+
+-- Apr 16, 2021, 9:55:50 PM CEST
+UPDATE AD_Column SET FKConstraintName='ADStorageProvider_ADAttachment', FKConstraintType='N',Updated=TO_TIMESTAMP('2021-04-16 21:55:50','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=214420
+;
+
+-- Apr 16, 2021, 9:55:50 PM CEST
+ALTER TABLE AD_Attachment ADD COLUMN AD_StorageProvider_ID NUMERIC(10) DEFAULT NULL
+;
+
+-- Apr 16, 2021, 9:55:50 PM CEST
+ALTER TABLE AD_Attachment ADD CONSTRAINT ADStorageProvider_ADAttachment FOREIGN KEY (AD_StorageProvider_ID) REFERENCES ad_storageprovider(ad_storageprovider_id) DEFERRABLE INITIALLY DEFERRED
+;
+
+-- Apr 16, 2021, 11:17:37 PM CEST
+INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,IsHtml) VALUES (214421,0,'Storage Provider',461,'AD_StorageProvider_ID',22,'N','N','N','N','N',0,'N',19,0,0,'Y',TO_TIMESTAMP('2021-04-16 23:17:37','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2021-04-16 23:17:37','YYYY-MM-DD HH24:MI:SS'),100,200238,'N','N','D','N','N','N','Y','ffac0527-d6d3-4a92-84cb-c15f7ac076c5','Y',0,'N','N','N')
+;
+
+-- Apr 16, 2021, 11:17:39 PM CEST
+UPDATE AD_Column SET FKConstraintName='ADStorageProvider_ADImage', FKConstraintType='N',Updated=TO_TIMESTAMP('2021-04-16 23:17:39','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=214421
+;
+
+-- Apr 16, 2021, 11:17:39 PM CEST
+ALTER TABLE AD_Image ADD COLUMN AD_StorageProvider_ID NUMERIC(10) DEFAULT NULL
+;
+
+-- Apr 16, 2021, 11:17:39 PM CEST
+ALTER TABLE AD_Image ADD CONSTRAINT ADStorageProvider_ADImage FOREIGN KEY (AD_StorageProvider_ID) REFERENCES ad_storageprovider(ad_storageprovider_id) DEFERRABLE INITIALLY DEFERRED
+;
+
+-- Apr 16, 2021, 11:18:35 PM CEST
+INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,FKConstraintType,IsHtml) VALUES (214422,0,'Storage Provider',754,'AD_StorageProvider_ID',22,'N','N','N','N','N',0,'N',19,0,0,'Y',TO_TIMESTAMP('2021-04-16 23:18:34','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2021-04-16 23:18:34','YYYY-MM-DD HH24:MI:SS'),100,200238,'N','N','D','N','N','N','Y','d15193c9-69cb-48de-94b4-5afeb82f405a','Y',0,'N','N','N','N')
+;
+
+-- Apr 16, 2021, 11:18:37 PM CEST
+UPDATE AD_Column SET FKConstraintName='ADStorageProvider_ADArchive', FKConstraintType='N',Updated=TO_TIMESTAMP('2021-04-16 23:18:37','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=214422
+;
+
+-- Apr 16, 2021, 11:18:37 PM CEST
+ALTER TABLE AD_Archive ADD COLUMN AD_StorageProvider_ID NUMERIC(10) DEFAULT NULL
+;
+
+-- Apr 16, 2021, 11:18:37 PM CEST
+ALTER TABLE AD_Archive ADD CONSTRAINT ADStorageProvider_ADArchive FOREIGN KEY (AD_StorageProvider_ID) REFERENCES ad_storageprovider(ad_storageprovider_id) DEFERRABLE INITIALLY DEFERRED
+;
+
+-- Apr 21, 2021, 5:36:53 PM CEST
+UPDATE AD_Process_Para SET SeqNo=90,Updated=TO_TIMESTAMP('2021-04-21 17:36:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200293
+;
+
+-- Apr 21, 2021, 5:37:39 PM CEST
+UPDATE AD_Process_Para SET DefaultValue='Y',Updated=TO_TIMESTAMP('2021-04-21 17:37:39','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200290
+;
+
+-- Apr 21, 2021, 5:37:43 PM CEST
+UPDATE AD_Process_Para SET DefaultValue='Y',Updated=TO_TIMESTAMP('2021-04-21 17:37:43','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200291
+;
+
+-- Apr 21, 2021, 5:37:46 PM CEST
+UPDATE AD_Process_Para SET DefaultValue='Y',Updated=TO_TIMESTAMP('2021-04-21 17:37:46','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200292
+;
+
+-- Apr 21, 2021, 5:39:08 PM CEST
+INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,Help,PrintName,EntityType,AD_Element_UU) VALUES (203483,0,0,'Y',TO_TIMESTAMP('2021-04-21 17:38:43','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2021-04-21 17:38:43','YYYY-MM-DD HH24:MI:SS'),100,'IsMigrateData','Migrate Data',NULL,NULL,'Migrate Data','D','cc8e6b76-fd73-4309-8fc6-2d9ead66d39d')
+;
+
+-- Apr 21, 2021, 5:39:16 PM CEST
+INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,DefaultValue,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted,IsAutocomplete) VALUES (200340,0,0,'Y',TO_TIMESTAMP('2021-04-21 17:39:15','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2021-04-21 17:39:15','YYYY-MM-DD HH24:MI:SS'),100,'Migrate Data',200117,70,20,'N',1,'Y','Y','IsMigrateData','Y','D',203483,'c060a763-cdf5-4b44-9486-5be5fb523674','N','N')
+;
+
+-- Apr 21, 2021, 5:42:35 PM CEST
+INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,Help,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted,MandatoryLogic,IsAutocomplete) VALUES (200341,0,0,'Y',TO_TIMESTAMP('2021-04-21 17:42:35','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2021-04-21 17:42:35','YYYY-MM-DD HH24:MI:SS'),100,'Record ID','Direct internal record ID','The Record ID is the internal unique identifier of a record. Please note that zooming to the record may not be successful for Orders, Invoices and Shipment/Receipts as sometimes the Sales Order type is not known.',200117,80,11,'Y',22,'N','Record_ID','Y','D',538,'c65e1cd9-1c1b-450c-a789-58feb9b7afe0','N',NULL,'N')
+;
+
+-- Apr 21, 2021, 5:54:28 PM CEST
+UPDATE AD_Process SET Help='WARNING: This process can be destructive, so please be sure that you have a backup of the database, as well as a backup of your old storage provider.
+
+The process migrates files between storage providers.
+
+- Client: Optional, select a client to migrate, when empty it will migrate all clients with the Actual Storage Provider
- Actual Storage Provider: Alternatively, you can define here the storage provider to migrate
- Storage Provider: The new storage provider to migrate the files
- Migrate Attachment: Migrate the attachment files
- Migrate Archive: Migate the archive files
- Migrate Image: Migrate the image files
- Migrate Data: When unchecked, just the storage provider is changed in client, but the files are not migrated (they can be migrated in a future execution of this same process)
- Record ID Range: Optionally you can define a range of IDs for the records to migrate, so you can run this process in parallel to migrate the data
- Delete old/existing files: If enabled, when a file is migrated the program tries to free space deleting the file from the previous storage provider. Note that migrating from/to a DB storage provider is a destructive action that cannot be recovered, it implies deleting the old/existing files.
+
+In case of failure or timeout, the process can be launched again, it commits on every file migrated.
',Updated=TO_TIMESTAMP('2021-04-21 17:54:28','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_ID=200117
+;
+
+-- set providers with actual values from client
+UPDATE ad_attachment a SET ad_storageprovider_id = (SELECT ci.ad_storageprovider_id FROM ad_clientinfo ci WHERE ci.ad_client_id=a.ad_client_id)
+WHERE a.ad_client_id IN (SELECT ad_client_id FROM ad_clientinfo WHERE ad_storageprovider_id IS NOT NULL);
+
+UPDATE ad_image i SET ad_storageprovider_id = (SELECT ci.storageimage_id FROM ad_clientinfo ci WHERE ci.ad_client_id=i.ad_client_id)
+WHERE ad_client_id IN (SELECT ad_client_id FROM ad_clientinfo WHERE storageimage_id IS NOT NULL);
+
+UPDATE ad_archive a SET ad_storageprovider_id = (SELECT ci.storagearchive_id FROM ad_clientinfo ci WHERE ci.ad_client_id=a.ad_client_id)
+WHERE ad_client_id IN (SELECT ad_client_id FROM ad_clientinfo WHERE storagearchive_id IS NOT NULL);
+
+SELECT register_migration_script('202104162211_IDEMPIERE-4762.sql') FROM dual
+;
+
diff --git a/org.adempiere.base.process/src/org/idempiere/process/MigrateStorageProvider.java b/org.adempiere.base.process/src/org/idempiere/process/MigrateStorageProvider.java
index 9633a927d6..813d1db697 100644
--- a/org.adempiere.base.process/src/org/idempiere/process/MigrateStorageProvider.java
+++ b/org.adempiere.base.process/src/org/idempiere/process/MigrateStorageProvider.java
@@ -1,4 +1,4 @@
-/**********************************************************************
+/***********************************************************************
* This file is part of iDempiere ERP Open Source *
* http://www.idempiere.org *
* *
@@ -28,8 +28,6 @@ package org.idempiere.process;
import java.sql.SQLException;
import java.sql.Timestamp;
-import java.util.ArrayList;
-import java.util.List;
import java.util.logging.Level;
import org.compiere.model.IArchiveStore;
@@ -57,6 +55,9 @@ public class MigrateStorageProvider extends SvrProcess {
private boolean p_IsMigrateAttachment = false;
private boolean p_IsMigrateArchive = false;
private boolean p_IsMigrateImage = false;
+ private boolean p_IsMigrateData = true;
+ private int p_IDFrom = 0;
+ private int p_IDTo = 0;
private boolean p_DeleteOld = false;
int cntAttachment = 0;
int cntArchive = 0;
@@ -82,6 +83,11 @@ public class MigrateStorageProvider extends SvrProcess {
p_IsMigrateArchive = para.getParameterAsBoolean();
} else if ("IsMigrateImage".equals(name)) {
p_IsMigrateImage = para.getParameterAsBoolean();
+ } else if ("IsMigrateData".equals(name)) {
+ p_IsMigrateData = para.getParameterAsBoolean();
+ } else if ("Record_ID".equals(name)) {
+ p_IDFrom = para.getParameterAsInt();
+ p_IDTo = para.getParameter_ToAsInt();
} else if ("DeleteOld".equals(name)) {
p_DeleteOld = para.getParameterAsBoolean();
} else {
@@ -103,18 +109,23 @@ public class MigrateStorageProvider extends SvrProcess {
+ ", IsMigrateAttachment=" + p_IsMigrateAttachment
+ ", IsMigrateArchive=" + p_IsMigrateArchive
+ ", IsMigrateImage=" + p_IsMigrateImage
+ + ", IsMigrateData=" + p_IsMigrateData
+ + ", IDFrom=" + p_IDFrom
+ + ", IDTo=" + p_IDTo
+ ", DeleteOld=" + p_DeleteOld);
if ( ! (p_IsMigrateAttachment || p_IsMigrateArchive || p_IsMigrateImage ) ) {
return "Nothing to migrate, please select an option";
}
+ MStorageProvider newProvider = MStorageProvider.get(getCtx(), p_AD_StorageProvider_ID);
+
// Create list of clients to process:
// - single AD_Client
// - clients using the actual storage provider (depending on the isMigrate flags)
- List clients = new ArrayList();
+ int[] clientsToUpdate;
if (p_AD_Client_ID >= 0) {
- clients.add(p_AD_Client_ID);
+ clientsToUpdate = new int[] {p_AD_Client_ID};
p_Actual_StorageProvider_ID = 0;
} else {
StringBuilder whereClause = new StringBuilder();
@@ -139,71 +150,90 @@ public class MigrateStorageProvider extends SvrProcess {
}
whereClause.append("StorageImage_ID").append(storageClause);
}
- int[] ids = new Query(getCtx(), MClientInfo.Table_Name, whereClause.toString(), get_TrxName())
+ clientsToUpdate = new Query(getCtx(), MClientInfo.Table_Name, whereClause.toString(), get_TrxName())
.setOrderBy("AD_Client_ID")
.getIDs();
- for (int id : ids) {
- clients.add(id);
- }
}
- if ( clients.size() == 0) {
- return "Nothing to migrate, no clients with that storage provider";
- }
- MStorageProvider newProvider = new MStorageProvider(getCtx(), p_AD_StorageProvider_ID, get_TrxName());
- boolean isNewStorageDB = MStorageProvider.METHOD_Database.equals(newProvider.getMethod());
- int idxClient = 0;
- int totalClients = clients.size();
- // for each client
- for (int clientid : clients) {
- idxClient++;
+ // Start the process updating the provider, data migration goes later
+ for (int clientid : clientsToUpdate) {
MClientInfo clientInfo = MClientInfo.getCopy(getCtx(), clientid, (String)null);
MClient client = MClient.get(getCtx(), clientid);
- int odometer = 10;
- if (p_IsMigrateAttachment) {
- if ( clientInfo.getAD_StorageProvider_ID() == p_AD_StorageProvider_ID
- || (clientInfo.getAD_StorageProvider_ID() == 0 && isNewStorageDB)) {
- String msg = client.getName() + " has already attachment storage " + newProvider.getName();
- addLog(msg);
- } else {
- migrateAttachments(newProvider, idxClient, totalClients, clientid, clientInfo, client, odometer);
- }
+ if ( p_IsMigrateAttachment
+ && clientInfo.getAD_StorageProvider_ID() != p_AD_StorageProvider_ID) {
+ clientInfo.setAD_StorageProvider_ID(p_AD_StorageProvider_ID);
+ clientInfo.saveEx();
+ String msg = "Attachment provider set to " + newProvider.getName() + " on " + client.getName();
+ addLog(msg);
}
- if (p_IsMigrateArchive) {
- if ( clientInfo.getStorageArchive_ID() == p_AD_StorageProvider_ID
- || (clientInfo.getStorageArchive_ID() == 0 && isNewStorageDB)) {
- String msg = client.getName() + " has already archive storage " + newProvider.getName();
- addLog(msg);
- } else {
- migrateArchives(newProvider, idxClient, totalClients, clientid, clientInfo, client, odometer);
- }
+ if ( p_IsMigrateArchive
+ && clientInfo.getStorageArchive_ID() != p_AD_StorageProvider_ID) {
+ clientInfo.setStorageArchive_ID(p_AD_StorageProvider_ID);
+ clientInfo.saveEx();
+ String msg = "Archive provider set to " + newProvider.getName() + " on " + client.getName();
+ addLog(msg);
}
- if (p_IsMigrateImage) {
- if ( clientInfo.getStorageImage_ID() == p_AD_StorageProvider_ID
- || (clientInfo.getStorageImage_ID() == 0 && isNewStorageDB)) {
- String msg = client.getName() + " has already image storage " + newProvider.getName();
- addLog(msg);
- } else {
- migrateImages(newProvider, idxClient, totalClients, clientid, clientInfo, client, odometer);
- }
+ if ( p_IsMigrateImage
+ && clientInfo.getStorageImage_ID() != p_AD_StorageProvider_ID) {
+ clientInfo.setStorageImage_ID(p_AD_StorageProvider_ID);
+ clientInfo.saveEx();
+ String msg = "Image provider set to " + newProvider.getName() + " on " + client.getName();
+ addLog(msg);
+ }
+ }
+ commitEx();
+ CacheMgt.get().reset(MClientInfo.Table_Name);
+
+ if (p_IsMigrateData) {
+ int[] clientsToMigrate;
+ if (p_AD_Client_ID >= 0) {
+ clientsToMigrate = new int[] {p_AD_Client_ID};
+ } else {
+ final String whereMigrate = "(AD_StorageProvider_ID=? OR StorageArchive_ID=? OR StorageImage_ID=?)";
+ clientsToMigrate = new Query(getCtx(), MClientInfo.Table_Name, whereMigrate, get_TrxName())
+ .setOrderBy("AD_Client_ID")
+ .setParameters(p_AD_StorageProvider_ID, p_AD_StorageProvider_ID, p_AD_StorageProvider_ID)
+ .getIDs();
}
- } // end for each client
+ int idxClient = 0;
+ int totalClients = clientsToMigrate.length;
+
+ // for each client
+ for (int clientid : clientsToMigrate) {
+ idxClient++;
+ MClient client = MClient.get(getCtx(), clientid);
+ int odometer = 10;
+
+ if (p_IsMigrateAttachment) {
+ migrateAttachments(newProvider, idxClient, totalClients, clientid, client, odometer);
+ }
+
+ if (p_IsMigrateArchive) {
+ migrateArchives(newProvider, idxClient, totalClients, clientid, client, odometer);
+ }
+
+ if (p_IsMigrateImage) {
+ migrateImages(newProvider, idxClient, totalClients, clientid, client, odometer);
+ }
+ } // end for each client
+
+ }
return "@Updated@ " + cntAttachment + " @AD_Attachment_ID@, " + cntArchive + " @AD_Archive_ID@, " + cntImage + " @AD_Image_ID@";
} // doIt
private void migrateAttachments(MStorageProvider newProvider, int idxClient, int totalClients, int clientid,
- MClientInfo clientInfo, MClient client, int odometer) throws SQLException {
+ MClient client, int odometer) throws SQLException {
// migrate attachment
status(idxClient, totalClients, "Migrating attachments for " + client.getName());
- int[] attachIds = new Query(getCtx(), MAttachment.Table_Name, "AD_Client_ID=?", get_TrxName())
- .setParameters(clientid)
+ final String where = "AD_Client_ID=? AND (?=0 OR AD_Attachment_ID>=?) AND (?=0 OR AD_Attachment_ID<=?) AND COALESCE(AD_StorageProvider_ID,0)!=?";
+ int[] attachIds = new Query(getCtx(), MAttachment.Table_Name, where, get_TrxName())
+ .setParameters(clientid, p_IDFrom, p_IDFrom, p_IDTo, p_IDTo, p_AD_StorageProvider_ID)
.setOrderBy("AD_Attachment_ID")
- .setForUpdate(true) // lock these records in the table
.getIDs();
int cntRecords = attachIds.length;
// iterate on each record of the associated table
@@ -214,55 +244,38 @@ public class MigrateStorageProvider extends SvrProcess {
progress(idxClient, totalClients, idxAttach, cntRecords, "Migrating attachment ");
}
MAttachment attachment = new MAttachment(getCtx(), attachId, get_TrxName());
+ int oldProviderId = attachment.getAD_StorageProvider_ID();
attachment.getEntries();
attachment.setStorageProvider(newProvider);
attachment.set_ValueNoCheck("Updated", new Timestamp(System.currentTimeMillis())); // to force save
// create file on the new storage provider
attachment.saveEx();
cntAttachment++;
- }
- // set the corresponding storage provider
- int oldProviderId = clientInfo.getAD_StorageProvider_ID();
- clientInfo.setAD_StorageProvider_ID(p_AD_StorageProvider_ID);
- clientInfo.saveEx();
- // cache reset
- CacheMgt.get().reset(MClientInfo.Table_Name, clientInfo.getAD_Client_ID());
- commitEx();
- String msg = "Migrated " + cntRecords + " attachments on " + client.getName();
- addLog(msg);
- // if delete old
- if (p_DeleteOld) {
- MStorageProvider oldProvider = new MStorageProvider(getCtx(), oldProviderId, get_TrxName());
- if (! (oldProviderId == 0 || MStorageProvider.METHOD_Database.equals(oldProvider.getMethod()))) {
- // DB method doesn't require delete
- IAttachmentStore oldStore = oldProvider.getAttachmentStore();
- // iterate on each record of the associated table
- idxAttach = 0;
- for (int attachId : attachIds) {
- idxAttach++;
- if (idxAttach % odometer == 0) {
- progress(idxClient, totalClients, idxAttach, cntRecords, "Deleting old attachment ");
- }
- // delete file on old storage
- MAttachment attachment = new MAttachment(getCtx(), attachId, get_TrxName());
- attachment.setStorageProvider(newProvider);
- attachment.getEntries();
+ // commit on every record migrated
+ commitEx();
+
+ if (p_DeleteOld) {
+ MStorageProvider oldProvider = MStorageProvider.get(getCtx(), oldProviderId);
+ if (! (oldProviderId == 0 || MStorageProvider.METHOD_Database.equals(oldProvider.getMethod()))) { // DB method doesn't require delete
+ IAttachmentStore oldStore = oldProvider.getAttachmentStore();
+ // delete file on old storage
oldStore.delete(attachment, oldProvider);
+ commitEx();
}
- msg = "Deleted " + cntRecords + " old attachment files on " + client.getName();
- addLog(msg);
}
}
+ String msg = "Migrated " + cntRecords + " attachments on " + client.getName();
+ addLog(msg);
}
private void migrateArchives(MStorageProvider newProvider, int idxClient, int totalClients, int clientid,
- MClientInfo clientInfo, MClient client, int odometer) throws SQLException {
+ MClient client, int odometer) throws SQLException {
// migrate archive
status(idxClient, totalClients, "Migrating archives for " + client.getName());
- int[] archiveIds = new Query(getCtx(), MArchive.Table_Name, "AD_Client_ID=?", get_TrxName())
- .setParameters(clientid)
+ final String where = "AD_Client_ID=? AND (?=0 OR AD_Archive_ID>=?) AND (?=0 OR AD_Archive_ID<=?) AND COALESCE(AD_StorageProvider_ID,0)!=?";
+ int[] archiveIds = new Query(getCtx(), MArchive.Table_Name, where, get_TrxName())
+ .setParameters(clientid, p_IDFrom, p_IDFrom, p_IDTo, p_IDTo, p_AD_StorageProvider_ID)
.setOrderBy("AD_Archive_ID")
- .setForUpdate(true) // lock these records in the table
.getIDs();
int cntRecords = archiveIds.length;
// iterate on each record of the associated table
@@ -273,6 +286,7 @@ public class MigrateStorageProvider extends SvrProcess {
progress(idxClient, totalClients, idxArchive, cntRecords, "Migrating archive ");
}
MArchive archive = new MArchive(getCtx(), archiveId, get_TrxName());
+ int oldProviderId = archive.getAD_StorageProvider_ID();
byte[] data = archive.getBinaryData();
archive.setStorageProvider(newProvider);
archive.setBinaryData(data);
@@ -280,48 +294,31 @@ public class MigrateStorageProvider extends SvrProcess {
// create file on the new storage provider
archive.saveEx();
cntArchive++;
- }
- // set the corresponding storage provider
- int oldProviderId = clientInfo.getStorageArchive_ID();
- clientInfo.setStorageArchive_ID(p_AD_StorageProvider_ID);
- clientInfo.saveEx();
- // cache reset
- CacheMgt.get().reset(MClientInfo.Table_Name, clientInfo.getAD_Client_ID());
- commitEx();
- String msg = "Migrated " + cntRecords + " archives on " + client.getName();
- addLog(msg);
- // if delete old
- if (p_DeleteOld) {
- MStorageProvider oldProvider = new MStorageProvider(getCtx(), oldProviderId, get_TrxName());
- if (! (oldProviderId == 0 || MStorageProvider.METHOD_Database.equals(oldProvider.getMethod()))) {
- // DB method doesn't require delete
- IArchiveStore oldStore = oldProvider.getArchiveStore();
- // iterate on each record of the associated table
- idxArchive = 0;
- for (int archiveId : archiveIds) {
- idxArchive++;
- if (idxArchive % odometer == 0) {
- progress(idxClient, totalClients, idxArchive, cntRecords, "Deleting old archive ");
- }
- // delete file on old storage
- MArchive archive = new MArchive(getCtx(), archiveId, get_TrxName());
- archive.setStorageProvider(newProvider);
+ // commit on every record migrated
+ commitEx();
+
+ if (p_DeleteOld) {
+ MStorageProvider oldProvider = MStorageProvider.get(getCtx(), oldProviderId);
+ if (! (oldProviderId == 0 || MStorageProvider.METHOD_Database.equals(oldProvider.getMethod()))) { // DB method doesn't require delete
+ IArchiveStore oldStore = oldProvider.getArchiveStore();
+ // delete file on old storage
oldStore.deleteArchive(archive, oldProvider);
+ commitEx();
}
- msg = "Deleted " + cntRecords + " old archive files on " + client.getName();
- addLog(msg);
}
}
+ String msg = "Migrated " + cntRecords + " archives on " + client.getName();
+ addLog(msg);
}
private void migrateImages(MStorageProvider newProvider, int idxClient, int totalClients, int clientid,
- MClientInfo clientInfo, MClient client, int odometer) throws SQLException {
+ MClient client, int odometer) throws SQLException {
// migrate image
status(idxClient, totalClients, "Migrating images for " + client.getName());
- int[] imageIds = new Query(getCtx(), MImage.Table_Name, "AD_Client_ID=?", get_TrxName())
- .setParameters(clientid)
+ final String where = "AD_Client_ID=? AND (?=0 OR AD_Image_ID>=?) AND (?=0 OR AD_Image_ID<=?) AND COALESCE(AD_StorageProvider_ID,0)!=?";
+ int[] imageIds = new Query(getCtx(), MImage.Table_Name, where, get_TrxName())
+ .setParameters(clientid, p_IDFrom, p_IDFrom, p_IDTo, p_IDTo, p_AD_StorageProvider_ID)
.setOrderBy("AD_Image_ID")
- .setForUpdate(true) // lock these records in the table
.getIDs();
int cntRecords = imageIds.length;
// iterate on each record of the associated table
@@ -332,45 +329,28 @@ public class MigrateStorageProvider extends SvrProcess {
progress(idxClient, totalClients, idxImage, cntRecords, "Migrating image ");
}
MImage image = new MImage(getCtx(), imageId, get_TrxName());
+ int oldProviderId = image.getAD_StorageProvider_ID();
byte[] data = image.getBinaryData();
image.setStorageProvider(newProvider);
image.setBinaryData(data);
image.set_ValueNoCheck("Updated", new Timestamp(System.currentTimeMillis())); // to force save
// create file on the new storage provider
image.saveEx();
- cntImage++;
- }
- // set the corresponding storage provider
- int oldProviderId = clientInfo.getStorageImage_ID();
- clientInfo.setStorageImage_ID(p_AD_StorageProvider_ID);
- clientInfo.saveEx();
- // cache reset
- CacheMgt.get().reset(MClientInfo.Table_Name, clientInfo.getAD_Client_ID());
- commitEx();
- String msg = "Migrated " + cntRecords + " images on " + client.getName();
- addLog(msg);
- // if delete old
- if (p_DeleteOld) {
- MStorageProvider oldProvider = new MStorageProvider(getCtx(), oldProviderId, get_TrxName());
- if (! (oldProviderId == 0 || MStorageProvider.METHOD_Database.equals(oldProvider.getMethod()))) {
- // DB method doesn't require delete
- IImageStore oldStore = oldProvider.getImageStore();
- // iterate on each record of the associated table
- idxImage = 0;
- for (int imageId : imageIds) {
- idxImage++;
- if (idxImage % odometer == 0) {
- progress(idxClient, totalClients, idxImage, cntRecords, "Deleting old image ");
- }
- // delete file on old storage
- MImage image = new MImage(getCtx(), imageId, get_TrxName());
- image.setStorageProvider(newProvider);
+ // commit on every record migrated
+ commitEx();
+
+ if (p_DeleteOld) {
+ MStorageProvider oldProvider = MStorageProvider.get(getCtx(), oldProviderId);
+ if (! (oldProviderId == 0 || MStorageProvider.METHOD_Database.equals(oldProvider.getMethod()))) { // DB method doesn't require delete
+ IImageStore oldStore = oldProvider.getImageStore();
+ // delete file on old storage
oldStore.delete(image, oldProvider);
+ commitEx();
}
- msg = "Deleted " + cntRecords + " old image files on " + client.getName();
- addLog(msg);
}
}
+ String msg = "Migrated " + cntRecords + " images on " + client.getName();
+ addLog(msg);
}
private void progress(int idxClient, int totalClients, int idxRecord, int cntRecords, String msg) {
diff --git a/org.adempiere.base/src/org/compiere/model/AttachmentFileSystem.java b/org.adempiere.base/src/org/compiere/model/AttachmentFileSystem.java
index 9990ae04f5..de6c5df870 100644
--- a/org.adempiere.base/src/org/compiere/model/AttachmentFileSystem.java
+++ b/org.adempiere.base/src/org/compiere/model/AttachmentFileSystem.java
@@ -48,7 +48,9 @@ import org.xml.sax.SAXException;
*
*/
public class AttachmentFileSystem implements IAttachmentStore {
-
+
+ // TODO: Implement FileSystemFallbackDB
+
private final CLogger log = CLogger.getCLogger(getClass());
@Override
diff --git a/org.adempiere.base/src/org/compiere/model/I_AD_Archive.java b/org.adempiere.base/src/org/compiere/model/I_AD_Archive.java
index 0ca9879398..5dd69755a4 100644
--- a/org.adempiere.base/src/org/compiere/model/I_AD_Archive.java
+++ b/org.adempiere.base/src/org/compiere/model/I_AD_Archive.java
@@ -99,6 +99,17 @@ public interface I_AD_Archive
public org.compiere.model.I_AD_Process getAD_Process() throws RuntimeException;
+ /** Column name AD_StorageProvider_ID */
+ public static final String COLUMNNAME_AD_StorageProvider_ID = "AD_StorageProvider_ID";
+
+ /** Set Storage Provider */
+ public void setAD_StorageProvider_ID (int AD_StorageProvider_ID);
+
+ /** Get Storage Provider */
+ public int getAD_StorageProvider_ID();
+
+ public org.compiere.model.I_AD_StorageProvider getAD_StorageProvider() throws RuntimeException;
+
/** Column name AD_Table_ID */
public static final String COLUMNNAME_AD_Table_ID = "AD_Table_ID";
diff --git a/org.adempiere.base/src/org/compiere/model/I_AD_Attachment.java b/org.adempiere.base/src/org/compiere/model/I_AD_Attachment.java
index 25166edb4f..ae7a7fbee8 100644
--- a/org.adempiere.base/src/org/compiere/model/I_AD_Attachment.java
+++ b/org.adempiere.base/src/org/compiere/model/I_AD_Attachment.java
@@ -84,6 +84,17 @@ public interface I_AD_Attachment
*/
public int getAD_Org_ID();
+ /** Column name AD_StorageProvider_ID */
+ public static final String COLUMNNAME_AD_StorageProvider_ID = "AD_StorageProvider_ID";
+
+ /** Set Storage Provider */
+ public void setAD_StorageProvider_ID (int AD_StorageProvider_ID);
+
+ /** Get Storage Provider */
+ public int getAD_StorageProvider_ID();
+
+ public org.compiere.model.I_AD_StorageProvider getAD_StorageProvider() throws RuntimeException;
+
/** Column name AD_Table_ID */
public static final String COLUMNNAME_AD_Table_ID = "AD_Table_ID";
diff --git a/org.adempiere.base/src/org/compiere/model/I_AD_Image.java b/org.adempiere.base/src/org/compiere/model/I_AD_Image.java
index 340ebc2ab6..b2e38dee70 100644
--- a/org.adempiere.base/src/org/compiere/model/I_AD_Image.java
+++ b/org.adempiere.base/src/org/compiere/model/I_AD_Image.java
@@ -84,6 +84,17 @@ public interface I_AD_Image
*/
public int getAD_Org_ID();
+ /** Column name AD_StorageProvider_ID */
+ public static final String COLUMNNAME_AD_StorageProvider_ID = "AD_StorageProvider_ID";
+
+ /** Set Storage Provider */
+ public void setAD_StorageProvider_ID (int AD_StorageProvider_ID);
+
+ /** Get Storage Provider */
+ public int getAD_StorageProvider_ID();
+
+ public org.compiere.model.I_AD_StorageProvider getAD_StorageProvider() throws RuntimeException;
+
/** Column name BinaryData */
public static final String COLUMNNAME_BinaryData = "BinaryData";
diff --git a/org.adempiere.base/src/org/compiere/model/MArchive.java b/org.adempiere.base/src/org/compiere/model/MArchive.java
index f31c86a4cb..855943b73b 100644
--- a/org.adempiere.base/src/org/compiere/model/MArchive.java
+++ b/org.adempiere.base/src/org/compiere/model/MArchive.java
@@ -153,8 +153,12 @@ public class MArchive extends X_AD_Archive {
* @param trxName
*/
private void initArchiveStoreDetails(Properties ctx, String trxName) {
- MClientInfo clientInfo = MClientInfo.get(ctx, getAD_Client_ID());
- provider=new MStorageProvider(ctx, clientInfo.getStorageArchive_ID(), trxName);
+ if (is_new()) {
+ MClientInfo clientInfo = MClientInfo.get(ctx, getAD_Client_ID());
+ setStorageProvider(MStorageProvider.get(ctx, clientInfo.getStorageArchive_ID()));
+ } else {
+ setStorageProvider(MStorageProvider.get(ctx, getAD_StorageProvider_ID()));
+ }
}
/**
@@ -302,6 +306,7 @@ public class MArchive extends X_AD_Archive {
*/
public void setStorageProvider(MStorageProvider p) {
provider = p;
+ setAD_StorageProvider_ID(p.getAD_StorageProvider_ID());
}
/**
diff --git a/org.adempiere.base/src/org/compiere/model/MAttachment.java b/org.adempiere.base/src/org/compiere/model/MAttachment.java
index ace7e5b395..899ed74147 100644
--- a/org.adempiere.base/src/org/compiere/model/MAttachment.java
+++ b/org.adempiere.base/src/org/compiere/model/MAttachment.java
@@ -169,8 +169,12 @@ public class MAttachment extends X_AD_Attachment
*/
private void initAttachmentStoreDetails(Properties ctx, String trxName)
{
- MClientInfo clientInfo = MClientInfo.get(ctx, getAD_Client_ID());
- provider=new MStorageProvider(ctx, clientInfo.getAD_StorageProvider_ID(), trxName);
+ if (is_new()) {
+ MClientInfo clientInfo = MClientInfo.get(ctx, getAD_Client_ID());
+ setStorageProvider(MStorageProvider.get(ctx, clientInfo.getAD_StorageProvider_ID()));
+ } else {
+ setStorageProvider(MStorageProvider.get(ctx, getAD_StorageProvider_ID()));
+ }
}
/**
@@ -705,6 +709,7 @@ public class MAttachment extends X_AD_Attachment
*/
public void setStorageProvider(MStorageProvider p) {
provider = p;
+ setAD_StorageProvider_ID(p.getAD_StorageProvider_ID());
}
} // MAttachment
diff --git a/org.adempiere.base/src/org/compiere/model/MImage.java b/org.adempiere.base/src/org/compiere/model/MImage.java
index 519ac24a91..7d0a9d6564 100644
--- a/org.adempiere.base/src/org/compiere/model/MImage.java
+++ b/org.adempiere.base/src/org/compiere/model/MImage.java
@@ -97,8 +97,11 @@ public class MImage extends X_AD_Image implements ImmutablePOSupport
public static MImage getCopy(Properties ctx, int AD_Image_ID, String trxName)
{
MImage img = get(AD_Image_ID);
- if (img != null && img.getAD_Image_ID() > 0)
+ if (img != null && img.getAD_Image_ID() > 0) {
+ MStorageProvider copyprov = img.provider;
img = new MImage(ctx, img, trxName);
+ img.setStorageProvider(copyprov);
+ }
return img;
}
@@ -399,8 +402,12 @@ public class MImage extends X_AD_Image implements ImmutablePOSupport
* @param trxName
*/
private void initImageStoreDetails(Properties ctx, String trxName) {
- MClientInfo clientInfo = MClientInfo.get(ctx, getAD_Client_ID());
- provider=new MStorageProvider(ctx, clientInfo.getStorageImage_ID(), trxName);
+ if (is_new()) {
+ MClientInfo clientInfo = MClientInfo.get(ctx, getAD_Client_ID());
+ setStorageProvider(MStorageProvider.get(ctx, clientInfo.getStorageImage_ID()));
+ } else {
+ setStorageProvider(MStorageProvider.get(ctx, getAD_StorageProvider_ID()));
+ }
}
/**
@@ -410,6 +417,7 @@ public class MImage extends X_AD_Image implements ImmutablePOSupport
*/
public void setStorageProvider(MStorageProvider p) {
provider = p;
+ setAD_StorageProvider_ID(p.getAD_StorageProvider_ID());
}
public byte[] getByteData(){
diff --git a/org.adempiere.base/src/org/compiere/model/MStorageProvider.java b/org.adempiere.base/src/org/compiere/model/MStorageProvider.java
index 08ca0772de..a02631a85e 100644
--- a/org.adempiere.base/src/org/compiere/model/MStorageProvider.java
+++ b/org.adempiere.base/src/org/compiere/model/MStorageProvider.java
@@ -25,13 +25,67 @@ import org.adempiere.base.ServiceQuery;
import org.adempiere.exceptions.AdempiereException;
import org.compiere.util.CCache;
import org.compiere.util.DB;
+import org.compiere.util.Env;
+import org.idempiere.cache.ImmutableIntPOCache;
+import org.idempiere.cache.ImmutablePOSupport;
-public class MStorageProvider extends X_AD_StorageProvider {
+public class MStorageProvider extends X_AD_StorageProvider implements ImmutablePOSupport {
/**
*
*/
- private static final long serialVersionUID = 6030898744999167572L;
+ private static final long serialVersionUID = -7444967391781941193L;
+ /** Cache */
+ static private ImmutableIntPOCache s_cache = new ImmutableIntPOCache(Table_Name, 10);
+
+ /**
+ * Get Storage Provider (cached) (immutable)
+ * @param AD_StorageProvider_ID id
+ * @return Storage Provider
+ */
+ public static MStorageProvider get (int AD_StorageProvider_ID)
+ {
+ return get(Env.getCtx(), AD_StorageProvider_ID);
+ }
+
+ /**
+ * Get Storage Provider (cached) (immutable)
+ * @param ctx context
+ * @param AD_StorageProvider_ID id
+ * @return Storage Provider
+ */
+ public static MStorageProvider get (Properties ctx, int AD_StorageProvider_ID)
+ {
+ Integer key = Integer.valueOf(AD_StorageProvider_ID);
+ MStorageProvider retValue = s_cache.get(ctx, key, e -> new MStorageProvider(ctx, e));
+ if (retValue == null)
+ {
+ retValue = new MStorageProvider (ctx, AD_StorageProvider_ID, null);
+ if (retValue.get_ID() == AD_StorageProvider_ID)
+ {
+ s_cache.put(key, retValue, e -> new MStorageProvider(Env.getCtx(), e));
+ return retValue;
+ }
+ return null;
+ }
+ return retValue;
+ } // get
+
+ /**
+ * Get updateable copy of MStorageProvider from cache
+ * @param ctx
+ * @param AD_StorageProvider_ID
+ * @param trxName
+ * @return MStorageProvider
+ */
+ public static MStorageProvider getCopy(Properties ctx, int AD_StorageProvider_ID, String trxName)
+ {
+ MStorageProvider rt = get(AD_StorageProvider_ID);
+ if (rt != null)
+ rt = new MStorageProvider(ctx, rt, trxName);
+ return rt;
+ }
+
public MStorageProvider(Properties ctx, int AD_StorageProvider_ID, String trxName) {
super(ctx, AD_StorageProvider_ID, trxName);
}
@@ -40,6 +94,37 @@ public class MStorageProvider extends X_AD_StorageProvider {
super(ctx, rs, trxName);
}
+ /**
+ *
+ * @param copy
+ */
+ public MStorageProvider(MStorageProvider copy)
+ {
+ this(Env.getCtx(), copy);
+ }
+
+ /**
+ *
+ * @param ctx
+ * @param copy
+ */
+ public MStorageProvider(Properties ctx, MStorageProvider copy)
+ {
+ this(ctx, copy, (String) null);
+ }
+
+ /**
+ *
+ * @param ctx
+ * @param copy
+ * @param trxName
+ */
+ public MStorageProvider(Properties ctx, MStorageProvider copy, String trxName)
+ {
+ this(ctx, 0, trxName);
+ copyPO(copy);
+ }
+
/**
*
* @return {@link IAttachmentStore}
@@ -174,4 +259,13 @@ public class MStorageProvider extends X_AD_StorageProvider {
return DB.getSQLValueEx(null, sql);
}
+ @Override
+ public MStorageProvider markImmutable() {
+ if (is_Immutable())
+ return this;
+
+ makeImmutable();
+ return this;
+ }
+
}
diff --git a/org.adempiere.base/src/org/compiere/model/X_AD_Archive.java b/org.adempiere.base/src/org/compiere/model/X_AD_Archive.java
index 91b31678e2..6fac9c6e93 100644
--- a/org.adempiere.base/src/org/compiere/model/X_AD_Archive.java
+++ b/org.adempiere.base/src/org/compiere/model/X_AD_Archive.java
@@ -30,7 +30,7 @@ public class X_AD_Archive extends PO implements I_AD_Archive, I_Persistent
/**
*
*/
- private static final long serialVersionUID = 20201220L;
+ private static final long serialVersionUID = 20210416L;
/** Standard Constructor */
public X_AD_Archive (Properties ctx, int AD_Archive_ID, String trxName)
@@ -138,6 +138,31 @@ public class X_AD_Archive extends PO implements I_AD_Archive, I_Persistent
return ii.intValue();
}
+ public org.compiere.model.I_AD_StorageProvider getAD_StorageProvider() throws RuntimeException
+ {
+ return (org.compiere.model.I_AD_StorageProvider)MTable.get(getCtx(), org.compiere.model.I_AD_StorageProvider.Table_Name)
+ .getPO(getAD_StorageProvider_ID(), get_TrxName()); }
+
+ /** Set Storage Provider.
+ @param AD_StorageProvider_ID Storage Provider */
+ public void setAD_StorageProvider_ID (int AD_StorageProvider_ID)
+ {
+ if (AD_StorageProvider_ID < 1)
+ set_ValueNoCheck (COLUMNNAME_AD_StorageProvider_ID, null);
+ else
+ set_ValueNoCheck (COLUMNNAME_AD_StorageProvider_ID, Integer.valueOf(AD_StorageProvider_ID));
+ }
+
+ /** Get Storage Provider.
+ @return Storage Provider */
+ public int getAD_StorageProvider_ID ()
+ {
+ Integer ii = (Integer)get_Value(COLUMNNAME_AD_StorageProvider_ID);
+ if (ii == null)
+ return 0;
+ return ii.intValue();
+ }
+
public org.compiere.model.I_AD_Table getAD_Table() throws RuntimeException
{
return (org.compiere.model.I_AD_Table)MTable.get(getCtx(), org.compiere.model.I_AD_Table.Table_Name)
diff --git a/org.adempiere.base/src/org/compiere/model/X_AD_Attachment.java b/org.adempiere.base/src/org/compiere/model/X_AD_Attachment.java
index 759df9fbd1..bd998f6111 100644
--- a/org.adempiere.base/src/org/compiere/model/X_AD_Attachment.java
+++ b/org.adempiere.base/src/org/compiere/model/X_AD_Attachment.java
@@ -30,7 +30,7 @@ public class X_AD_Attachment extends PO implements I_AD_Attachment, I_Persistent
/**
*
*/
- private static final long serialVersionUID = 20201220L;
+ private static final long serialVersionUID = 20210416L;
/** Standard Constructor */
public X_AD_Attachment (Properties ctx, int AD_Attachment_ID, String trxName)
@@ -110,6 +110,31 @@ public class X_AD_Attachment extends PO implements I_AD_Attachment, I_Persistent
return (String)get_Value(COLUMNNAME_AD_Attachment_UU);
}
+ public org.compiere.model.I_AD_StorageProvider getAD_StorageProvider() throws RuntimeException
+ {
+ return (org.compiere.model.I_AD_StorageProvider)MTable.get(getCtx(), org.compiere.model.I_AD_StorageProvider.Table_Name)
+ .getPO(getAD_StorageProvider_ID(), get_TrxName()); }
+
+ /** Set Storage Provider.
+ @param AD_StorageProvider_ID Storage Provider */
+ public void setAD_StorageProvider_ID (int AD_StorageProvider_ID)
+ {
+ if (AD_StorageProvider_ID < 1)
+ set_ValueNoCheck (COLUMNNAME_AD_StorageProvider_ID, null);
+ else
+ set_ValueNoCheck (COLUMNNAME_AD_StorageProvider_ID, Integer.valueOf(AD_StorageProvider_ID));
+ }
+
+ /** Get Storage Provider.
+ @return Storage Provider */
+ public int getAD_StorageProvider_ID ()
+ {
+ Integer ii = (Integer)get_Value(COLUMNNAME_AD_StorageProvider_ID);
+ if (ii == null)
+ return 0;
+ return ii.intValue();
+ }
+
public org.compiere.model.I_AD_Table getAD_Table() throws RuntimeException
{
return (org.compiere.model.I_AD_Table)MTable.get(getCtx(), org.compiere.model.I_AD_Table.Table_Name)
diff --git a/org.adempiere.base/src/org/compiere/model/X_AD_Image.java b/org.adempiere.base/src/org/compiere/model/X_AD_Image.java
index d7df4c9c1e..35198992ed 100644
--- a/org.adempiere.base/src/org/compiere/model/X_AD_Image.java
+++ b/org.adempiere.base/src/org/compiere/model/X_AD_Image.java
@@ -30,7 +30,7 @@ public class X_AD_Image extends PO implements I_AD_Image, I_Persistent
/**
*
*/
- private static final long serialVersionUID = 20201220L;
+ private static final long serialVersionUID = 20210416L;
/** Standard Constructor */
public X_AD_Image (Properties ctx, int AD_Image_ID, String trxName)
@@ -110,6 +110,31 @@ public class X_AD_Image extends PO implements I_AD_Image, I_Persistent
return (String)get_Value(COLUMNNAME_AD_Image_UU);
}
+ public org.compiere.model.I_AD_StorageProvider getAD_StorageProvider() throws RuntimeException
+ {
+ return (org.compiere.model.I_AD_StorageProvider)MTable.get(getCtx(), org.compiere.model.I_AD_StorageProvider.Table_Name)
+ .getPO(getAD_StorageProvider_ID(), get_TrxName()); }
+
+ /** Set Storage Provider.
+ @param AD_StorageProvider_ID Storage Provider */
+ public void setAD_StorageProvider_ID (int AD_StorageProvider_ID)
+ {
+ if (AD_StorageProvider_ID < 1)
+ set_ValueNoCheck (COLUMNNAME_AD_StorageProvider_ID, null);
+ else
+ set_ValueNoCheck (COLUMNNAME_AD_StorageProvider_ID, Integer.valueOf(AD_StorageProvider_ID));
+ }
+
+ /** Get Storage Provider.
+ @return Storage Provider */
+ public int getAD_StorageProvider_ID ()
+ {
+ Integer ii = (Integer)get_Value(COLUMNNAME_AD_StorageProvider_ID);
+ if (ii == null)
+ return 0;
+ return ii.intValue();
+ }
+
/** Set Binary Data.
@param BinaryData
Binary Data
diff --git a/org.adempiere.pipo/src/org/adempiere/pipo2/PoExporter.java b/org.adempiere.pipo/src/org/adempiere/pipo2/PoExporter.java
index 3669f17220..5f996dbbd8 100644
--- a/org.adempiere.pipo/src/org/adempiere/pipo2/PoExporter.java
+++ b/org.adempiere.pipo/src/org/adempiere/pipo2/PoExporter.java
@@ -305,7 +305,7 @@ public class PoExporter {
if ("BinaryData".equals(columnName)) {
MClientInfo ci = MClientInfo.get(po.getAD_Client_ID());
if (po.get_Table_ID() == MAttachment.Table_ID && ci.getAD_StorageProvider_ID() > 0) {
- MStorageProvider sp = new MStorageProvider(po.getCtx(), ci.getAD_StorageProvider_ID(), po.get_TrxName());
+ MStorageProvider sp = MStorageProvider.get(po.getCtx(), ci.getAD_StorageProvider_ID());
if (! MStorageProvider.METHOD_Database.equals(sp.getMethod())) {
MAttachment att = new MAttachment(po.getCtx(), po.get_ID(), po.get_TrxName());
File tmpfile = att.saveAsZip();
@@ -316,13 +316,13 @@ public class PoExporter {
}
}
} else if (po.get_Table_ID() == MImage.Table_ID && ci.getStorageImage_ID() > 0) {
- MStorageProvider sp = new MStorageProvider(po.getCtx(), ci.getStorageImage_ID(), po.get_TrxName());
+ MStorageProvider sp = MStorageProvider.get(po.getCtx(), ci.getStorageImage_ID());
if (! MStorageProvider.METHOD_Database.equals(sp.getMethod())) {
MImage image = new MImage(po.getCtx(), po.get_ID(), po.get_TrxName());
value = image.getBinaryData();
}
} else if (po.get_Table_ID() == MArchive.Table_ID && ci.getStorageArchive_ID() > 0) {
- MStorageProvider sp = new MStorageProvider(po.getCtx(), ci.getStorageArchive_ID(), po.get_TrxName());
+ MStorageProvider sp = MStorageProvider.get(po.getCtx(), ci.getStorageArchive_ID());
if (! MStorageProvider.METHOD_Database.equals(sp.getMethod())) {
MArchive archive = new MArchive(po.getCtx(), po.get_ID(), po.get_TrxName());
File tmpfile = archive.saveAsZip();