All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openestate.is24.restapi.utils.ExportHandler Maven / Gradle / Ivy

/*
 * Copyright 2014-2017 OpenEstate.org.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.openestate.is24.restapi.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.xml.bind.JAXBException;
import oauth.signpost.exception.OAuthException;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.openestate.is24.restapi.AbstractClient;
import org.openestate.is24.restapi.ImportExport;
import org.openestate.is24.restapi.xml.common.Attachment;
import org.openestate.is24.restapi.xml.common.Attachments;
import org.openestate.is24.restapi.xml.common.Link;
import org.openestate.is24.restapi.xml.common.Message;
import org.openestate.is24.restapi.xml.common.MessageCode;
import org.openestate.is24.restapi.xml.common.Messages;
import org.openestate.is24.restapi.xml.common.PDFDocument;
import org.openestate.is24.restapi.xml.common.Picture;
import org.openestate.is24.restapi.xml.common.PublishChannel;
import org.openestate.is24.restapi.xml.common.PublishChannels;
import org.openestate.is24.restapi.xml.common.PublishObject;
import org.openestate.is24.restapi.xml.common.PublishObjects;
import org.openestate.is24.restapi.xml.common.RealEstateState;
import org.openestate.is24.restapi.xml.common.RealtorContactDetails;
import org.openestate.is24.restapi.xml.common.StreamingVideo;
import org.openestate.is24.restapi.xml.offerlistelement.OfferRealEstateForList;
import org.openestate.is24.restapi.xml.offerlistelement.RealEstateList;
import org.openestate.is24.restapi.xml.realestates.RealEstate;
import org.openestate.is24.restapi.xml.realestates.RealEstates;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Handler for bulk exports.
 * 

* The {@link ExportHandler} is part of the high level API for bulk exports of real * estate data. *

* A previously created {@link ExportPool} can be processed with the * {@link ExportHandler#export(org.openestate.is24.restapi.AbstractClient, org.openestate.is24.restapi.utils.ExportPool, boolean, boolean)} * method. The {@link ExportHandler} will launch the required low level * operations of the {@link ImportExport}-API for each pooled object. * * @since 0.2 * @author Andreas Rudolph */ public class ExportHandler { private final static Logger LOGGER = LoggerFactory.getLogger( ExportHandler.class ); private final List messages = new ArrayList(); private final List savedContactIds = new ArrayList(); private final Map duplicatedContactIds = new HashMap(); private AbstractClient client = null; private ExportPool pool = null; private long progress = 0; private long totalProgress = 0; private boolean useNewEnergySourceEnev2014Values = true; private boolean removeObjectBeforeUpdate = false; /** * Create a new {@link ExportHandler}. */ public ExportHandler() { } /** * Calback method to track progress during the export process. *

* This method may be overridden by inheriting classes in order to track the * progress of the export process. * * @param value * value of additional progress */ protected final void addProgress( long value ) { this.setProgress( this.progress + Math.abs( value ) ); } /** * Callback method to check, if a contact should be updated in the export process. * * @param contact * contact person to update * * @param poolContactId * id of the contact person within export pool * * @return * true, if the contact person can be ignored in the export process */ protected boolean canIgnoreContact( RealtorContactDetails contact, String poolContactId ) { return false; } /** * Callback method to check, if a real estate should be updated in the export process. * * @param object * real estate to update * * @param poolObjectId * id of the real estate within export pool * * @return * true, if the real estate can be ignored in the export process */ protected boolean canIgnoreObject( RealEstate object, String poolObjectId ) { return false; } /** * Archivate a real estate object at the Webservice. * * @param externalObjectId * external real estate ID * * @throws IOException * if the operation failed */ protected final void doArchiveObject( String externalObjectId ) throws IOException { // Immobilie ermitteln final RealEstate is24Object; try { is24Object = ImportExport.RealEstateService.getByExternalId( this.client, externalObjectId ); if (is24Object==null) { this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_NOT_FOUND_FOR_ARCHIVING, "Property '" + externalObjectId + "' is not available anymore at the Webservice!" ); return; } } catch (JAXBException ex) { throw new IOException( "Can't read / write XML while communicating with the Webservice!", ex ); } catch (OAuthException ex) { throw new IOException( "Authorization failed!", ex ); } catch (RequestFailedException ex) { LOGGER.error( "Can't get property '" + externalObjectId + "' from the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_NOT_FOUND_FOR_ARCHIVING, ex ); return; } this.doArchiveObject( is24Object ); } /** * Archivate a real estate object at the Webservice. * * @param is24ObjectId * real estate ID by IS24 * * @param externalObjectId * external real estate ID * * @throws IOException * if the operation failed */ protected final void doArchiveObject( long is24ObjectId, String externalObjectId ) throws IOException { // Immobilie ermitteln final RealEstate is24Object; try { is24Object = ImportExport.RealEstateService.getByIs24Id( this.client, is24ObjectId ); if (is24Object==null) { if (!StringUtils.isBlank( externalObjectId )) { this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_NOT_FOUND_FOR_ARCHIVING, "Property '" + externalObjectId + "' is not available anymore at the Webservice!" ); } else { this.putGeneralMessage( ExportMessage.Code.OBJECT_NOT_FOUND_FOR_ARCHIVING, "Property (" + is24ObjectId + ") is not available anymore at the Webservice!" ); } return; } } catch (JAXBException ex) { throw new IOException( "Can't read / write XML while communicating with the Webservice!", ex ); } catch (OAuthException ex) { throw new IOException( "Authorization failed!", ex ); } catch (RequestFailedException ex) { if (!StringUtils.isBlank( externalObjectId )) { LOGGER.error( "Can't get property '" + externalObjectId + "' (" + is24ObjectId + ") from the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_NOT_FOUND_FOR_ARCHIVING, ex ); } else { LOGGER.error( "Can't get property (" + is24ObjectId + ") from the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putGeneralMessage( ExportMessage.Code.OBJECT_NOT_FOUND_FOR_ARCHIVING, ex ); } return; } this.doArchiveObject( is24Object ); } /** * Archivate a real estate object at the Webservice. * * @param is24Object * real estate to archivate * * @throws IOException * if the operation failed */ protected void doArchiveObject( RealEstate is24Object ) throws IOException { try { final Long is24ObjectId = is24Object.getId(); final String externalObjectId = StringUtils.trimToNull( is24Object.getExternalId() ); // aktuelle Veröffentlichungen zur Immobilie ermitteln PublishObjects is24Publishings = null; try { is24Publishings = ImportExport.PublishService.get( this.client, is24ObjectId, 0 ); } catch (RequestFailedException ex) { if (!StringUtils.isBlank( externalObjectId )) { LOGGER.error( "Can't get publishings of property '" + externalObjectId + "' (" + is24ObjectId + ") from the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_PUBLISHINGS_NOT_FOUND, ex ); } else { LOGGER.error( "Can't get publishings of property (" + is24ObjectId + ") from the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putGeneralMessage( ExportMessage.Code.OBJECT_PUBLISHINGS_NOT_FOUND, ex ); } } // keine Veröffentlichungen gefunden if (is24Publishings==null) { if (!StringUtils.isBlank( externalObjectId )) { this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_PUBLISHINGS_NOT_FOUND, "Can't get publishings of property '" + externalObjectId + "' (" + is24ObjectId + ") from the Webservice!" ); } else { this.putGeneralMessage( ExportMessage.Code.OBJECT_PUBLISHINGS_NOT_FOUND, "Can't get publishings of property (" + is24ObjectId + ") from the Webservice!" ); } } // ggf. Veröffentlichungen der Immobilie entfernen else { for (PublishObject publishing : is24Publishings.getPublishObject()) { Long is24ChannelId = publishing.getPublishChannel().getId(); String publishId = StringUtils.trimToNull( publishing.getId() ); try { ImportExport.PublishService.delete( this.client, publishId ); } catch (RequestFailedException ex) { if (!StringUtils.isBlank( externalObjectId )) { LOGGER.error( "Can't unpublish property '" + externalObjectId + "' (" + is24ObjectId + ") " + "in channel '" + publishing.getPublishChannel().getTitle() + "' (" + is24ChannelId + ") at the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_NOT_UNPUBLISHED, ex ); } else { LOGGER.error( "Can't unpublish property (" + is24ObjectId + ") " + "in channel '" + publishing.getPublishChannel().getTitle() + "' (" + is24ChannelId + ") at the Webservice!" ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putGeneralMessage( ExportMessage.Code.OBJECT_NOT_UNPUBLISHED, ex ); } } } } } catch (JAXBException ex) { throw new IOException( "Can't read / write XML while communicating with the Webservice!", ex ); } catch (OAuthException ex) { throw new IOException( "Authorization failed!", ex ); } catch (IOException ex) { throw new IOException( "Communication failed!", ex ); } } /** * Download an {@link URL} into a {@link File}. * * @param url * URL to download * * @return * downloaded file * * @throws IOException * if the operation failed */ protected File doDownloadFile( URL url ) throws IOException { if (url==null) return null; LOGGER.info( "downloading " + url ); InputStream input = null; OutputStream output = null; try { input = url.openStream(); File tempFile = File.createTempFile( "is24-export-attachment-", ".bin" ); tempFile.deleteOnExit(); output = new FileOutputStream( tempFile ); IOUtils.copy( input, output ); output.flush(); return tempFile; } finally { IOUtils.closeQuietly( output ); IOUtils.closeQuietly( input ); } } /** * Return internal and external ID's of published real estates from the * Webservice, that were not changed during the current export process. * * @return * mapping of internal and external ID's of untouched real estates * * @throws IOException * if the operation failed */ protected Map doListUntouchedObjects() throws IOException { try { final Map ids = new TreeMap(); // Immobilien im Bestand ermitteln int page = 1; while (true) { RealEstates is24Objects; try { is24Objects = ImportExport.RealEstateService.getAll( this.client, null, null, 0, page, false ); if (is24Objects==null) { this.putGeneralMessage( ExportMessage.Code.OBJECTS_NOT_FOUND, "Can't get available properties from the Webservice!" ); return new HashMap(); } } catch (RequestFailedException ex) { LOGGER.error( "Can't get available properties from the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putGeneralMessage( ExportMessage.Code.OBJECTS_NOT_FOUND, ex ); return new HashMap(); } Long totalPages = is24Objects.getPaging().getNumberOfPages(); if (totalPages==null) totalPages = 0L; RealEstateList is24ObjectList = is24Objects.getRealEstateList(); if (is24ObjectList!=null && !is24ObjectList.getRealEstateElement().isEmpty()) { for (OfferRealEstateForList is24Object : is24ObjectList.getRealEstateElement()) { // Immobilien nur löschen, // wenn diese als "aktiv" bei IS24 markiert sind. // // TODO: Es ist hier nicht ganz klar, aus welchem XML-Element // der Immobilien-Status zu ermitteln ist. boolean isActive = RealEstateState.ACTIVE.equals( is24Object.getState() ) || RealEstateState.ACTIVE.equals( is24Object.getRealEstateState() ); if (!isActive) continue; // Immobilien nur zurückliefern, // wenn diese beim Exportvorgang nicht verändert wurden. long is24ObjectId = is24Object.getId(); String externalObjectId = is24Object.getExternalId(); if (!ids.containsKey( is24ObjectId ) && !this.pool.hasObjectForExport( externalObjectId )) { ids.put( is24ObjectId, externalObjectId ); } } } if (page>=totalPages) break; page++; } return ids; } catch (JAXBException ex) { throw new IOException( "Can't read / write XML while communicating with the Webservice!", ex ); } catch (OAuthException ex) { throw new IOException( "Authorization failed!", ex ); } catch (IOException ex) { throw new IOException( "Communication failed!", ex ); } } /** * Return publish channels for the authorized agency. * * @return * publish channels * * @throws IOException * if the operation failed */ protected PublishChannels doLoadPublishChannels() throws IOException { try { return ImportExport.PublishChannelService.get( this.client ); } catch (RequestFailedException ex) { LOGGER.error( "Can't get publish channels from the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putGeneralMessage( ExportMessage.Code.PUBLISH_CHANNELS_NOT_FOUND, ex ); return null; } catch (JAXBException ex) { //LOGGER.error( "Can't read / write XML while communicating with the Webservice!" ); //LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); throw new IOException( "Can't read / write XML while communicating with the Webservice!", ex ); } catch (OAuthException ex) { //LOGGER.error( "Can't authorize at the Webservice!" ); //LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); throw new IOException( "Authorization failed!", ex ); } catch (IOException ex) { //LOGGER.error( "Can't communicate with the Webservice!" ); //LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); throw new IOException( "Communication failed!", ex ); } } /** * Publish a real estate at the Webservice. * * @param is24ObjectId * real estate ID by IS24 * * @param externalObjectId * external real estate ID * * @param is24PublishChannels * channels, where the real estate should be published * * @throws IOException * if the operation failed */ protected void doPublishObject( long is24ObjectId, String externalObjectId, PublishChannels is24PublishChannels ) throws IOException { final org.openestate.is24.restapi.xml.common.ObjectFactory commonFactory = new org.openestate.is24.restapi.xml.common.ObjectFactory(); try { // derzeitige Veröffentlichungen zur Immobilie ermitteln final List is24PublishedChannels = new ArrayList(); try { PublishObjects is24Publishings = ImportExport.PublishService.get( this.client, is24ObjectId, 0 ); if (is24Publishings!=null) { for (PublishObject is24Publishing : is24Publishings.getPublishObject()) { is24PublishedChannels.add( is24Publishing.getPublishChannel().getId() ); } } } catch (RequestFailedException ex) { LOGGER.error( "Can't get publishings of property '" + externalObjectId + "' (" + is24ObjectId + ") from the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_PUBLISHINGS_NOT_FOUND, ex ); } if (is24PublishChannels==null) { this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_NOT_PUBLISHED, "No channels for publishing found!" ); } else { // Veröffentlichungen zur Immobilie aktualisieren, // wenn diese zu einem Kanal noch nicht gesetzt wurde for (PublishChannel is24Channel : is24PublishChannels.getPublishChannel()) { Long is24ChannelId = is24Channel.getId(); if (is24PublishedChannels.contains( is24ChannelId )) continue; PublishObject is24Publishing = commonFactory.createPublishObject(); is24Publishing.setPublishChannel( is24Channel ); is24Publishing.setRealEstate( commonFactory.createPublishObjectRealEstate() ); is24Publishing.getRealEstate().setId( is24ObjectId ); try { ImportExport.PublishService.post( this.client, is24Publishing ); } catch (RequestFailedException ex) { LOGGER.error( "Can't publish property '" + externalObjectId + "' (" + is24ObjectId + ") " + "in channel '" + is24Channel.getTitle() + "' (" + is24ChannelId + ")!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_NOT_PUBLISHED, ex ); } } } } catch (JAXBException ex) { //LOGGER.error( "Can't read / write XML while communicating with the Webservice!" ); //LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); throw new IOException( "Can't read / write XML while communicating with the Webservice!", ex ); } catch (OAuthException ex) { //LOGGER.error( "Can't authorize at the Webservice!" ); //LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); throw new IOException( "Authorization failed!", ex ); } catch (IOException ex) { //LOGGER.error( "Can't communicate with the Webservice!" ); //LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); throw new IOException( "Communication failed!", ex ); } } /** * Remove a real estate object from the Webservice. * * @param externalObjectId * external real estate ID * * @throws IOException * if the operation failed */ protected void doRemoveObject( String externalObjectId ) throws IOException { try { // Löschung durchführen try { ImportExport.RealEstateService.deleteByExternalId( this.client, externalObjectId ); } catch (RequestFailedException ex) { LOGGER.error( "Can't delete property '" + externalObjectId + "' at the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_NOT_REMOVED, ex ); } } catch (JAXBException ex) { throw new IOException( "Can't read / write XML while communicating with the Webservice!", ex ); } catch (OAuthException ex) { throw new IOException( "Authorization failed!", ex ); } catch (IOException ex) { throw new IOException( "Communication failed!", ex ); } } /** * Remove a real estate object from the Webservice. * * @param is24ObjectId * real estate ID by IS24 * * @param externalObjectId * external real estate ID * * @throws IOException * if the operation failed */ protected void doRemoveObject( long is24ObjectId, String externalObjectId ) throws IOException { try { // Löschung durchführen try { ImportExport.RealEstateService.deleteByIs24Id( this.client, is24ObjectId ); } catch (RequestFailedException ex) { if (!StringUtils.isBlank( externalObjectId )) { LOGGER.error( "Can't delete property '" + externalObjectId + "' (" + is24ObjectId + ") at the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_NOT_REMOVED, ex ); } else { LOGGER.error( "Can't delete property (" + is24ObjectId + ") at the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putGeneralMessage( ExportMessage.Code.OBJECT_NOT_REMOVED, ex ); } } } catch (JAXBException ex) { throw new IOException( "Can't read / write XML while communicating with the Webservice!", ex ); } catch (OAuthException ex) { throw new IOException( "Authorization failed!", ex ); } catch (IOException ex) { throw new IOException( "Communication failed!", ex ); } } /** * Save a contact person to the Webservice. * * @param contact * contact to save * * @param poolContactId * contact ID within export pool * * @return * ID of the processed contact person in the Webservice or null, if the object * was not updated * * @throws IOException * if the operation failed */ protected Long doUpdateContact( RealtorContactDetails contact, String poolContactId ) throws IOException { final String externalContactId = contact.getExternalId(); try { // prüfen, ob ein Ansprechpartner mit der externen ID bereits im Webservice existiert final RealtorContactDetails oldIs24Contact; try { oldIs24Contact = ImportExport.ContactAddressService.getByExternalId( this.client, externalContactId ); } catch (RequestFailedException ex) { LOGGER.error( "Can't get contact person '" + externalContactId + "' from the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putContactMessage( externalContactId, ExportMessage.Code.CONTACT_NOT_FOUND, ex ); return null; } Long is24ContactId; // neuen Ansprechpartner erstellen if (oldIs24Contact==null) { try { is24ContactId = ImportExport.ContactAddressService.post( this.client, contact ); } catch (RequestFailedException ex) { Resource resource = Resource.getMessageResource( ex.responseMessages ); if (resource!=null && "duplicated contactDetails".equalsIgnoreCase( resource.type ) && resource.id>0) { LOGGER.info( "contact '" + externalContactId + "' is already " + "available at the Webservice with ID " + resource.id + "." ); this.duplicatedContactIds.put( externalContactId, resource.id ); is24ContactId = resource.id; } else { LOGGER.error( "Can't add contact person '" + externalContactId + "' to the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putContactMessage( externalContactId, ExportMessage.Code.CONTACT_NOT_SAVED, ex ); return null; } } } // bestehenden Ansprechpartner aktualisieren else { is24ContactId = oldIs24Contact.getId(); contact.setId( is24ContactId ); try { ImportExport.ContactAddressService.putByIs24Id( this.client, contact, is24ContactId ); } catch (RequestFailedException ex) { Resource resource = Resource.getMessageResource( ex.responseMessages ); if (resource!=null && "duplicated contactDetails".equalsIgnoreCase( resource.type ) && resource.id>0) { LOGGER.info( "contact '" + externalContactId + "' is already " + "available at the Webservice with ID " + resource.id + "." ); this.duplicatedContactIds.put( externalContactId, resource.id ); return resource.id; } else { LOGGER.error( "Can't update contact person '" + externalContactId + "' at the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putContactMessage( externalContactId, ExportMessage.Code.CONTACT_NOT_SAVED, ex ); return null; } } } // ID des Ansprechpartners als erfolgreich exportiert vormerken this.savedContactIds.add( externalContactId ); // ID des verarbeiteten Ansprechpartners bei IS24 zurückliefern return is24ContactId; } catch (JAXBException ex) { throw new IOException( "Can't read / write XML while communicating with the Webservice!", ex ); } catch (OAuthException ex) { throw new IOException( "Authorization failed!", ex ); } catch (IOException ex) { throw new IOException( "Communication failed!", ex ); } finally { // Fortschritt protokollieren this.addProgress( this.pool.getContactSize( poolContactId, true ) ); } } /** * Save a real estate to the Webservice. * * @param object * real estate to save * * @param poolObjectId * real estate ID within export pool * * @return * ID of the processed real estate in the Webservice or null, if the object * was not updated * * @throws IOException * if the operation failed */ protected Long doUpdateObject( RealEstate object, String poolObjectId ) throws IOException { final String externalObjectId = object.getExternalId(); final org.openestate.is24.restapi.xml.realestates.ObjectFactory realEstatesFactory = new org.openestate.is24.restapi.xml.realestates.ObjectFactory(); final org.openestate.is24.restapi.xml.attachmentsorder.ObjectFactory attachmentsorderFactory = new org.openestate.is24.restapi.xml.attachmentsorder.ObjectFactory(); object.setRealEstateState( RealEstateState.ACTIVE ); // Ansprechpartner zuweisen, wenn nicht bereits explizit eine intene // Ansprechpartner-ID hinterlegt wurde Long is24ContactId = (object.getContact()!=null)? object.getContact().getId(): null; if (is24ContactId==null || is24ContactId<1) { String externalContactId = (object.getContact()!=null)? StringUtils.trimToNull( object.getContact().getExternalId() ): null; // Duplikat des Ansprechpartners verwenden if (externalContactId!=null && this.duplicatedContactIds.containsKey( externalContactId )) { is24ContactId = this.duplicatedContactIds.get( externalContactId ); if (object.getContact()==null) object.setContact( realEstatesFactory.createRealEstateContact() ); object.getContact().setId( is24ContactId ); object.getContact().setExternalId( null ); } // sicherstellen, dass der Ansprechpartner vorher erfolgreich während des Transports exportiert wurde else if (externalContactId!=null && !this.savedContactIds.contains( externalContactId )) { this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_WITHOUT_CONTACT, "The contact '" + externalContactId + "' was not saved during the export process." ); object.setContact( null ); } } try { // prüfen, ob eine Immobilie mit der externen ID bereits im Webservice existiert RealEstate oldIs24Object; try { oldIs24Object = ImportExport.RealEstateService.getByExternalId( this.client, externalObjectId ); } catch (RequestFailedException ex) { LOGGER.error( "Can't get property '" + externalObjectId + "' from the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_NOT_FOUND, ex ); // Fortschritt protokollieren this.addProgress( this.pool.getObjectSize( poolObjectId, true ) ); return null; } //Messages responseMessages; final Long is24ObjectId; // Immobilie im Portal löschen, // wenn diese bereits in einer anderen Rubrik im Portal existiert // oder wenn dies explizit angefordert wurde if (oldIs24Object!=null && (this.removeObjectBeforeUpdate || !oldIs24Object.getClass().getName().equals( object.getClass().getName() ))) { //LOGGER.debug( "RUBRIK GEÄNDERT" ); //LOGGER.debug( "> für Immobilie #" + oldIs24Object.getId() ); //LOGGER.debug( "> alte Rubrik " + oldIs24Object.getClass().getName() ); //LOGGER.debug( "> neue Rubrik " + object.getClass().getName() ); try { ImportExport.RealEstateService.deleteByIs24Id( this.client, oldIs24Object.getId() ); oldIs24Object = null; } catch (RequestFailedException ex) { LOGGER.error( "Can't delete property '" + externalObjectId + "' (" + oldIs24Object.getId() + ") at the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_NOT_SAVED, ex ); // Fortschritt protokollieren this.addProgress( this.pool.getObjectSize( poolObjectId, true ) ); return null; } } // neue Immobilie erstellen if (oldIs24Object==null) { try { is24ObjectId = ImportExport.RealEstateService.post( this.client, object, this.isUseNewEnergySourceEnev2014Values() ); //LOGGER.debug( "created object with IS24-ID #" + is24ObjectId ); } catch (RequestFailedException ex) { LOGGER.error( "Can't add property '" + externalObjectId + "' to the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_NOT_SAVED, ex ); // Fortschritt protokollieren this.addProgress( this.pool.getObjectSize( poolObjectId, true ) ); return null; } } // bestehende Immobilie aktualisieren else { is24ObjectId = oldIs24Object.getId(); object.setId( is24ObjectId ); try { ImportExport.RealEstateService.putByIs24Id( this.client, object, is24ObjectId, this.isUseNewEnergySourceEnev2014Values() ); //LOGGER.debug( "updated object with IS24-ID #" + is24ObjectId ); } catch (RequestFailedException ex) { LOGGER.error( "Can't update property '" + externalObjectId + "' (" + is24ObjectId + ") at the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_NOT_SAVED, ex ); // Fortschritt protokollieren this.addProgress( this.pool.getObjectSize( poolObjectId, true ) ); return null; } } // Fortschritt protokollieren this.addProgress( this.pool.getObjectSize( poolObjectId, false ) ); // bestehende Anhänge / Web-Links ermitteln final Map oldIs24Attachments = new HashMap(); boolean ignoreAttachments = false; try { Attachments attachments = ImportExport.AttachmentService.getAll( this.client, externalObjectId ); if (attachments!=null && !attachments.getAttachment().isEmpty()) { for (Attachment attachment : attachments.getAttachment()) { Long is24AttachmentId = attachment.getId(); String externalAttachmentId = StringUtils.trimToNull( attachment.getExternalId() ); // Anhang übernehmen, wenn ein Hashwert hinterlegt ist // und dieser noch nicht übernommen wurde if (externalAttachmentId!=null && !oldIs24Attachments.containsKey( externalAttachmentId )) { //LOGGER.debug( "> found old attachment #" + is24AttachmentId + " / " + externalAttachmentId + " / " + externalAttachmentId.length() ); oldIs24Attachments.put( externalAttachmentId, attachment ); continue; } // alten Anhang entfernen try { //LOGGER.debug( "> removing old attachment #" + is24AttachmentId + " without external id" ); ImportExport.AttachmentService.deleteById( this.client, externalObjectId, is24AttachmentId ); } catch (RequestFailedException ex) { LOGGER.error( "Can't remove old attachment (" + is24AttachmentId + ") " + "of property '" + externalObjectId + "' (" + is24ObjectId + ") from the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_OLD_ATTACHMENT_NOT_REMOVED, ex ); } } } } catch (RequestFailedException ex) { LOGGER.error( "Can't get attachments of property '" + externalObjectId + "' (" + is24ObjectId + ") from the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_WITHOUT_ATTACHMENTS, ex ); ignoreAttachments = true; } if (ignoreAttachments) { // Fortschritt protokollieren long totalAttachmentSize = this.pool.getObjectSize( poolObjectId, true ) - this.pool.getObjectSize( poolObjectId, false ); this.addProgress( totalAttachmentSize ); } else { // Anhänge zur Übertragung ermitteln und zugehörige Hash-Werte berechnen List attachmentHashes = new ArrayList(); Map attachments = new TreeMap( new AlphanumComparator() ); Map attachmentFiles = new HashMap(); for (String attachmentKey : this.pool.getObjectAttachmentIds( poolObjectId )) { Attachment is24Attachment; String parserError = null; try { is24Attachment = this.pool.getObjectAttachment( poolObjectId, attachmentKey ); } catch (Exception ex) { LOGGER.error( "Can't read XML for attachment '" + attachmentKey + "' of object '" + poolObjectId + "'!" ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); is24Attachment = null; parserError = StringUtils.trimToNull( ExceptionUtils.getRootCauseMessage( ex ) ); } if (is24Attachment==null) { LOGGER.error( "Can't read the XML for attachment!" ); String msg = "Can't read the XML for attachment!"; if (parserError!=null) msg += " (" + parserError + ")"; this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_ATTACHMENT_NOT_SAVED, msg ); // Fortschritt protokollieren this.addProgress( this.pool.getObjectAttachmentSize( poolObjectId, attachmentKey ) ); continue; } // Anhang als Web-Link verarbeiten if (is24Attachment instanceof Link) { Link link = (Link) is24Attachment; // Hashwert zur Identifizierung des Anhangs errechnen URL url = link.getUrl(); String externalAttachmentId = (url!=null)? DigestUtils.sha1Hex( is24ObjectId + "-" + url.toString() ): DigestUtils.sha1Hex( is24ObjectId + "-" + attachmentKey ); // Sicherstellen, dass der gleiche Anhang nicht mehrfach hochgeladen wird if (attachmentHashes.contains( externalAttachmentId )) continue; attachmentHashes.add( externalAttachmentId ); link.setExternalId( externalAttachmentId ); } // Anhang als Datei verarbeiten else { // Datei ermitteln File attachFile = this.pool.getObjectAttachmentFile( poolObjectId, is24Attachment ); // ggf. Datei herunterladen, wenn noch nicht im Pool hinterlegt if (attachFile==null) { URL attachUrl = this.pool.getObjectAttachmentURL( is24Attachment ); if (attachUrl!=null) { try { attachFile = doDownloadFile( attachUrl ); } catch (Exception ex) { LOGGER.warn( "Can't download file from URL: " + attachUrl ); LOGGER.warn( "> " + ex.getLocalizedMessage(), ex ); } } } if (attachFile==null || !attachFile.isFile()) { LOGGER.error( "Can't find file for attachment!" ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_ATTACHMENT_NOT_SAVED, "Can't find file for attachment!" ); // Fortschritt protokollieren this.addProgress( this.pool.getObjectAttachmentSize( poolObjectId, attachmentKey ) ); continue; } // Datei des Anhangs vormerken attachmentFiles.put( attachmentKey, attachFile.getAbsoluteFile() ); // Hashwert zur Identifizierung des Anhangs errechnen final String externalAttachmentId; InputStream input = null; try { input = new FileInputStream( attachFile ); String attachFileHash = DigestUtils.sha1Hex( input ); externalAttachmentId = DigestUtils.sha1Hex( is24ObjectId + "-" + attachFileHash ); // Sicherstellen, dass der gleiche Anhang nicht mehrfach hochgeladen wird if (attachmentHashes.contains( externalAttachmentId )) continue; attachmentHashes.add( externalAttachmentId ); is24Attachment.setExternalId( externalAttachmentId ); } finally { IOUtils.closeQuietly( input ); } } attachments.put( attachmentKey, is24Attachment ); } // alte Anhänge entfernen String[] oldIs24AttachmentIds = oldIs24Attachments.keySet().toArray( new String[oldIs24Attachments.size()] ); for (String oldIs24AttachmentId : oldIs24AttachmentIds) { if (attachmentHashes.contains( oldIs24AttachmentId )) continue; Attachment is24Attachment = oldIs24Attachments.remove( oldIs24AttachmentId ); Long is24AttachmentId = is24Attachment.getId(); try { //LOGGER.debug( "> removing old attachment #" + is24AttachmentId ); ImportExport.AttachmentService.deleteById( this.client, externalObjectId, is24AttachmentId ); } catch (RequestFailedException ex) { LOGGER.error( "Can't remove old attachment (" + is24AttachmentId + ") " + "of property '" + externalObjectId + "' (" + is24ObjectId + ") from the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_OLD_ATTACHMENT_NOT_REMOVED, ex ); } } // Anhänge aus dem Exportverzeichnis der Immobilie ermitteln Map attachmentsOrder = new TreeMap(); for (Map.Entry entry : attachments.entrySet()) { final String attachmentKey = entry.getKey(); final Attachment is24Attachment = entry.getValue(); final String externalAttachmentId = is24Attachment.getExternalId(); int pos; try { pos = Math.abs( Integer.parseInt( attachmentKey ) ); } catch (NumberFormatException ex) { LOGGER.warn( "Can't read attachment position!" ); LOGGER.warn( "> " + ex.getLocalizedMessage(), ex ); pos = 999; } // Anhang als Web-Link verarbeiten if (is24Attachment instanceof Link) { Link link = (Link) is24Attachment; try { // zuvor gespeicherten Web-Link mit gleichem Hashwert aktualisieren if (oldIs24Attachments.containsKey( externalAttachmentId )) { Attachment oldAttachment = oldIs24Attachments.get( externalAttachmentId ); long is24AttachmentId = oldAttachment.getId(); //LOGGER.debug( "> updating attached link #" + is24AttachmentId ); //LOGGER.debug( ">> " + externalAttachmentId + " / " + externalAttachmentId.length() ); ImportExport.AttachmentService.putById( this.client, is24ObjectId, is24AttachmentId, link ); oldIs24Attachments.remove( externalAttachmentId ); } // neuen Web-Link erzeugen else { //LOGGER.debug( "> adding attached link" ); //LOGGER.debug( ">> " + externalAttachmentId + " / " + externalAttachmentId.length() ); ImportExport.AttachmentService.post( this.client, externalObjectId, is24Attachment, null, null, null ); } } catch (RequestFailedException ex) { LOGGER.error( "Can't save attachment of property '" + externalObjectId + "' (" + is24ObjectId + ") to the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_ATTACHMENT_NOT_SAVED, ex ); } // Fortschritt protokollieren this.addProgress( this.pool.getObjectAttachmentSize( poolObjectId, attachmentKey ) ); continue; } // Datei ermitteln File attachFile = attachmentFiles.get( attachmentKey ); if (attachFile==null || !attachFile.isFile()) { LOGGER.error( "Can't find file for attachment!" ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_ATTACHMENT_NOT_SAVED, "Can't find file for attachment!" ); // Fortschritt protokollieren this.addProgress( this.pool.getObjectAttachmentSize( poolObjectId, attachmentKey ) ); continue; } // Name und Größe des Dateianhangs ermitteln final String attachFileName = attachFile.getName(); final long attachFileSize = attachFile.length(); InputStream attachFileInput = null; try { // zuvor gespeicherten Anhang mit gleichem Hashwert aktualisieren if (oldIs24Attachments.containsKey( externalAttachmentId )) { Attachment oldAttachment = oldIs24Attachments.get( externalAttachmentId ); long is24AttachmentId = oldAttachment.getId(); //LOGGER.debug( "> updating attached file #" + is24AttachmentId ); //LOGGER.debug( ">> " + externalAttachmentId + " / " + externalAttachmentId.length() ); ImportExport.AttachmentService.putById( this.client, is24ObjectId, is24AttachmentId, is24Attachment ); oldIs24Attachments.remove( externalAttachmentId ); // Sortierung des Anhangs vormerken if (!StreamingVideo.class.isInstance( is24Attachment )) { while (attachmentsOrder.containsKey( pos )) { pos++; } attachmentsOrder.put( pos, is24AttachmentId ); //LOGGER.debug( "untouched attachment #" + is24AttachmentId + " (" + StringUtils.trimToEmpty( is24Attachment.getTitle() ) + ") at " + pos ); } } // neuen Anhang erzeugen else { //LOGGER.debug( "> adding attached file" ); //LOGGER.debug( ">> " + externalAttachmentId + " / " + externalAttachmentId.length() ); // MIME-Type des Dateianhangs ermitteln final String attachFileMimeType; if (is24Attachment instanceof PDFDocument) { attachFileMimeType = "application/pdf"; } else if (is24Attachment instanceof Picture) { if (attachFileName.toLowerCase().endsWith( ".png" )) attachFileMimeType = "image/png"; else if (attachFileName.toLowerCase().endsWith( ".gif" )) attachFileMimeType = "image/gif"; else attachFileMimeType = "image/jpeg"; } //else if (is24Attachment instanceof VideoFile) //{ // mimeType = "application/octet-stream"; //} else { //mimeType = "application/octet-stream"; attachFileMimeType = null; } attachFileInput = new FileInputStream( attachFile ); // Video auf separaten Webservice übertragen if (is24Attachment instanceof StreamingVideo) { // Videodatei via UploadService übertragen //LOGGER.debug( "UPLOAD STREAMING VIDEO '" + attachFileName + "'" ); String videoId = ImportExport.VideoUploadService.doVideoUpload( this.client, attachFileInput, attachFileName, attachFileSize ); // Anhang mit ID des übertragenen Videos zum Webservice senden //LOGGER.debug( "POST STREAMING VIDEO WITH ID '" + videoId + "'" ); StreamingVideo streamingVideo = (StreamingVideo) is24Attachment; streamingVideo.setVideoId( videoId ); ImportExport.AttachmentService.post( this.client, externalObjectId, streamingVideo, null, null, null ); } // Anhang direkt übertragen else { long is24AttachmentId = ImportExport.AttachmentService.post( this.client, externalObjectId, is24Attachment, attachFileInput, attachFileName, attachFileMimeType ); // Sortierung des Anhangs vormerken while (attachmentsOrder.containsKey( pos )) { pos++; } attachmentsOrder.put( pos, is24AttachmentId ); //LOGGER.debug( "new attachment #" + is24AttachmentId + " (" + StringUtils.trimToEmpty( is24Attachment.getTitle() ) + ") at " + pos ); } } } catch (RequestFailedException ex) { LOGGER.error( "Can't save attachment of property '" + externalObjectId + "' (" + is24ObjectId + ") to the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_ATTACHMENT_NOT_SAVED, ex ); } finally { IOUtils.closeQuietly( attachFileInput ); // Fortschritt protokollieren this.addProgress( this.pool.getObjectAttachmentSize( poolObjectId, attachmentKey ) + attachFileSize ); } } // nicht aktualisierte Anhänge entfernen for (Attachment is24Attachment : oldIs24Attachments.values()) { Long is24AttachmentId = is24Attachment.getId(); try { //LOGGER.debug( "> removing untouched attachment #" + is24AttachmentId ); ImportExport.AttachmentService.deleteById( this.client, externalObjectId, is24AttachmentId ); } catch (RequestFailedException ex) { LOGGER.error( "Can't remove untouched attachment (" + is24AttachmentId + ") " + "of property '" + externalObjectId + "' (" + is24ObjectId + ") from the Webservice!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_OLD_ATTACHMENT_NOT_REMOVED, ex ); } } // Reihenfolge der Bild-Anhänge setzen if (!attachmentsOrder.isEmpty()) { //LOGGER.debug( "update attachment order for property '" + externalObjectId + "' (" + is24ObjectId + ")" ); //LOGGER.debug( "> " + StringUtils.join( attachmentsOrder.values(), ", " ) ); org.openestate.is24.restapi.xml.attachmentsorder.List list = attachmentsorderFactory.createList(); for (Long is24AttachmentId : attachmentsOrder.values()) { list.getAttachmentId().add( is24AttachmentId ); } try { ImportExport.AttachmentsOrderService.put( this.client, externalObjectId, list ); } catch (RequestFailedException ex) { LOGGER.error( "Can't order attachments of property '" + externalObjectId + "' (" + is24ObjectId + ")!" ); if (ex.requestRefNumber!=null) LOGGER.error( "> referring request: " + ex.requestRefNumber ); logMessagesAsError( ex.responseMessages ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); this.putObjectMessage( externalObjectId, ExportMessage.Code.OBJECT_UNORDERED_ATTACHMENTS, ex ); } } } return is24ObjectId; } catch (JAXBException ex) { //LOGGER.error( "Can't read / write XML while communicating with the Webservice!" ); //LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); throw new IOException( "Can't read / write XML while communicating with the Webservice!", ex ); } catch (OAuthException ex) { //LOGGER.error( "Can't authorize at the Webservice!" ); //LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); throw new IOException( "Authorization failed!", ex ); } catch (IOException ex) { //LOGGER.error( "Can't communicate with the Webservice!" ); //LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); throw new IOException( "Communication failed!", ex ); } } /** * Start the bulk export of an {@link ExportPool}. * * @param client * client, that is used for transfers * * @param pool * pool with exportable data * * @param disableUnpublishedObjects * disable old real estates instead of removal * * @param unpublishUntouchedObjects * archivate or remove untouched real estates (means full transfer instead of * incremental) * * @return * messages, that occured during the export process * * @throws IOException * if the operation failed */ public ExportMessage[] export( AbstractClient client, ExportPool pool, boolean disableUnpublishedObjects, boolean unpublishUntouchedObjects ) throws IOException { this.client = client; this.pool = pool; this.messages.clear(); this.savedContactIds.clear(); this.duplicatedContactIds.clear(); // init progress this.totalProgress = this.pool.getTotalSize(); this.setProgress( 0 ); // updating contacts Map is24ObjectIds = new HashMap(); String[] ids = this.pool.getContactIds(); if (!ArrayUtils.isEmpty( ids )) { LOGGER.info( "updating contacts" ); int counter = 0; for (String poolContactId : ids) { counter++; // Ansprechpartner ermitteln RealtorContactDetails contact; String parserError = null; try { contact = this.pool.getContact( poolContactId ); } catch (Exception ex) { LOGGER.error( "Can't read XML for contact '" + poolContactId + "'!" ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); contact = null; parserError = StringUtils.trimToNull( ExceptionUtils.getRootCauseMessage( ex ) ); } if (contact==null) { // Fortschritt protokollieren this.addProgress( this.pool.getContactSize( poolContactId, true ) ); String msg = "Can't read XML for contact '" + poolContactId + "'!"; if (parserError!=null) msg += " (" + parserError + ")"; this.putGeneralMessage( ExportMessage.Code.XML_NOT_READABLE, msg ); } else if (this.canIgnoreContact( contact, poolContactId )) { LOGGER.info( "[" + counter + " / " + ids.length +"] " + "ignoring contact '" + contact.getExternalId() + "'" ); this.savedContactIds.add( contact.getExternalId() ); // Fortschritt protokollieren this.addProgress( this.pool.getContactSize( poolContactId, true ) ); } else { LOGGER.info( "[" + counter + " / " + ids.length +"] " + "updating contact '" + contact.getExternalId() + "'" ); this.doUpdateContact( contact, poolContactId ); } } } // updating objects ids = this.pool.getObjectIds(); if (!ArrayUtils.isEmpty( ids )) { LOGGER.info( "updating objects" ); int counter = 0; for (String poolObjectId : ids) { counter++; // Immobilie aus ExportPool ermitteln RealEstate object; String parserError = null; try { object = this.pool.getObject( poolObjectId ); } catch (Exception ex) { LOGGER.error( "Can't read XML for property '" + poolObjectId + "'!" ); LOGGER.error( "> " + ex.getLocalizedMessage(), ex ); object = null; parserError = StringUtils.trimToNull( ExceptionUtils.getRootCauseMessage( ex ) ); } if (object==null) { // Fortschritt protokollieren this.addProgress( this.pool.getObjectSize( poolObjectId, true ) ); String msg = "Can't read XML for property '" + poolObjectId + "'!"; if (parserError!=null) msg += " (" + parserError + ")"; this.putGeneralMessage( ExportMessage.Code.XML_NOT_READABLE, msg ); } else if (this.canIgnoreObject( object, poolObjectId )) { LOGGER.info( "[" + counter + " / " + ids.length +"] " + "ignoring object '" + object.getExternalId() + "'" ); // Fortschritt protokollieren this.addProgress( this.pool.getObjectSize( poolObjectId, true ) ); } else { LOGGER.info( "[" + counter + " / " + ids.length +"] " + "updating object '" + object.getExternalId() + "'" ); Long is24ObjectId = this.doUpdateObject( object, poolObjectId ); if (is24ObjectId!=null) { is24ObjectIds.put( is24ObjectId, StringUtils.trimToNull( object.getExternalId() ) ); } } } } // removing objects ids = this.pool.getObjectIdsForRemoval(); if (!ArrayUtils.isEmpty( ids )) { LOGGER.info( "removing objects" ); int counter = 0; for (String externalObjectId : ids) { counter++; if (disableUnpublishedObjects) { LOGGER.info( "[" + counter + " / " + ids.length +"] " + "archiving object '" + externalObjectId + "'" ); this.doArchiveObject( externalObjectId ); } else { LOGGER.info( "[" + counter + " / " + ids.length +"] " + "removing object '" + externalObjectId + "'" ); this.doRemoveObject( externalObjectId ); } } } // removing untouched objects if (unpublishUntouchedObjects) { LOGGER.info( "looking for untouched objects" ); Map untouchedObjectIds = this.doListUntouchedObjects(); final int untouchedObjectCount = untouchedObjectIds.size(); int counter = 0; for (Map.Entry entry : untouchedObjectIds.entrySet()) { counter++; long is24ObjectId = entry.getKey(); String externalObjectId = entry.getValue(); if (disableUnpublishedObjects) { LOGGER.info( "[" + counter + " / " + untouchedObjectCount +"] " + "archiving untouched object '" + externalObjectId + "' (" + is24ObjectId + ")" ); this.doArchiveObject( is24ObjectId, externalObjectId ); } else { LOGGER.info( "[" + counter + " / " + untouchedObjectCount +"] " + "removing untouched object '" + externalObjectId + "' (" + is24ObjectId + ")" ); this.doRemoveObject( is24ObjectId, externalObjectId ); } } } if (!is24ObjectIds.isEmpty()) { // load available publish channels LOGGER.info( "loading publish channels" ); final PublishChannels publishChannels = doLoadPublishChannels(); // publishing objects LOGGER.info( "publishing objects" ); int counter = 0; for (Map.Entry entry : is24ObjectIds.entrySet()) { counter++; Long is24ObjectId = entry.getKey(); String externalObjectId = entry.getValue(); LOGGER.info( "[" + counter + " / " + is24ObjectIds.size() +"] " + "publishing object '" + externalObjectId + "' (" + is24ObjectId + ")" ); doPublishObject( is24ObjectId, externalObjectId, publishChannels ); } } return this.getMessages(); } /** * Return the client of the current export process. * * @return * client */ protected final AbstractClient getClient() { return client; } /** * Return messages, that occured during the last export process. * * @return * messages */ public final ExportMessage[] getMessages() { return this.messages.toArray( new ExportMessage[this.messages.size()] ); } /** * Return messages for a certain contact person, that occured during the last * export process. * * @param externalContactId * external contact ID * * @return * messages */ public final ExportMessage[] getMessagesForContact( String externalContactId ) { externalContactId = StringUtils.trimToNull( externalContactId ); if (externalContactId==null) return new ExportMessage[]{}; List msgs = new ArrayList(); for (ExportMessage msg : this.messages) { if (externalContactId.equals( msg.getContactId() )) msgs.add( msg ); } return msgs.toArray( new ExportMessage[msgs.size()] ); } /** * Return messages for a certain real estate, that occured during the last * export process. * * @param externalObjectId * real estate ID * * @return * messages */ public final ExportMessage[] getMessagesForObject( String externalObjectId ) { externalObjectId = StringUtils.trimToNull( externalObjectId ); if (externalObjectId==null) return new ExportMessage[]{}; List msgs = new ArrayList(); for (ExportMessage msg : this.messages) { if (externalObjectId.equals( msg.getObjectId() )) msgs.add( msg ); } return msgs.toArray( new ExportMessage[msgs.size()] ); } /** * Return general messages, that occured during the last export process. * * @return * messages */ public final ExportMessage[] getMessagesGeneral() { List msgs = new ArrayList(); for (ExportMessage msg : this.messages) { if (msg.isGeneral()) msgs.add( msg ); } return msgs.toArray( new ExportMessage[msgs.size()] ); } /** * Return the {@link ExportPool} of the current export process. * * @return * pool */ protected final ExportPool getPool() { return pool; } /** * Return the progress of the current export process. * * @return * current progress value */ protected final long getProgress() { return progress; } /** * Return the total progress of the current export process. * * @return * total progress value */ protected final long getTotalProgress() { return totalProgress; } /** * Check, if objects are removed before update. * * @return * true, if objects are removed before update. */ public boolean isRemoveObjectBeforeUpdate() { return this.removeObjectBeforeUpdate; } /** * Check, if all values for "energySourceEnev2014" are enabled. * * @return * true, if all values for "energySourceEnev2014" are enabled * * @see notes about Energy Certificate 2014 */ public boolean isUseNewEnergySourceEnev2014Values() { return this.useNewEnergySourceEnev2014Values; } /** * Send {@link Messages} from a Webservice response to the local logger. * * @param messages * messages */ private void logMessagesAsError( Messages messages ) { if (messages==null || messages.getMessage().isEmpty()) return; for (Message m : messages.getMessage()) { LOGGER.error( "> " + m.getMessageCode() + " | " + m.getMessage() ); } } /** * Calback method, that is called after the progress has changed. *

* This method may be overridden by inheriting classes in order to track the * progress of the export process. * * @param progress * current progress value * * @param totalProgress * total progress value */ protected void progressUpdated( long progress, long totalProgress ) { } /** * Register a message for a contact person. * * @param externalContactId * external contact ID * * @param code * message code * * @param msg * message text */ protected final void putContactMessage( String externalContactId, ExportMessage.Code code, String msg ) { this.putContactMessage( externalContactId, code, msg, null ); } /** * Register a message for a contact person. * * @param externalContactId * external contact ID * * @param code * message code * * @param msg * message text * * @param errorRequestRefNumber * unique identifier of the failed HTTP request */ protected void putContactMessage( String externalContactId, ExportMessage.Code code, String msg, String errorRequestRefNumber ) { this.messages.add( ExportMessage.newContactMessage( externalContactId, code, msg, errorRequestRefNumber ) ); } /** * Register error messages for a contact person. * * @param externalContactId * external contact ID * * @param code * message code * * @param ex * exception of the failed request */ protected final void putContactMessage( String externalContactId, ExportMessage.Code code, RequestFailedException ex ) { if (ex==null || ex.responseMessages==null) return; for (Message message : ex.responseMessages.getMessage()) { MessageCode is24Code = message.getMessageCode(); String is24Msg = StringUtils.trimToNull( message.getMessage() ); String txt = StringUtils.EMPTY; if (is24Code!=null) txt += is24Code.value(); if (is24Msg!=null) { if (!StringUtils.isBlank( txt )) txt += " | "; txt += is24Msg; } this.putContactMessage( externalContactId, code, txt, ex.requestRefNumber ); } } /** * Register a general message. * * @param code * message code * * @param msg * message text */ protected final void putGeneralMessage( ExportMessage.Code code, String msg ) { this.putGeneralMessage( code, msg, null ); } /** * Register a general message. * * @param code * message code * * @param msg * message text * * @param errorRequestRefNumber * unique identifier of the failed HTTP request */ protected void putGeneralMessage( ExportMessage.Code code, String msg, String errorRequestRefNumber ) { this.messages.add( ExportMessage.newGeneralMessage( msg, code, errorRequestRefNumber ) ); } /** * Register general error messages. * * @param code * message code * * @param ex * exception of the failed request */ protected final void putGeneralMessage( ExportMessage.Code code, RequestFailedException ex ) { if (ex==null || ex.responseMessages==null) return; for (Message message : ex.responseMessages.getMessage()) { MessageCode is24Code = message.getMessageCode(); String is24Msg = StringUtils.trimToNull( message.getMessage() ); String txt = StringUtils.EMPTY; if (is24Code!=null) txt += is24Code.value(); if (is24Msg!=null) { if (!StringUtils.isBlank( txt )) txt += " | "; txt += is24Msg; } this.putGeneralMessage( code, txt, ex.requestRefNumber ); } } /** * Register a message for a real estate. * * @param externalObjectId * external real estate ID * * @param code * message code * * @param msg * message text */ protected final void putObjectMessage( String externalObjectId, ExportMessage.Code code, String msg ) { this.putObjectMessage( externalObjectId, code, msg, null ); } /** * Register a message for a real estate. * * @param externalObjectId * external real estate ID * * @param code * message code * * @param msg * message text * * @param errorRequestRefNumber * unique identifier of the failed HTTP request */ protected void putObjectMessage( String externalObjectId, ExportMessage.Code code, String msg, String errorRequestRefNumber ) { this.messages.add( ExportMessage.newObjectMessage( externalObjectId, code, msg, errorRequestRefNumber ) ); } /** * Register error messages for a real estate. * * @param externalObjectId * external real estate ID * * @param code * message code * * @param ex * exception of the failed request */ protected final void putObjectMessage( String externalObjectId, ExportMessage.Code code, RequestFailedException ex ) { if (ex==null || ex.responseMessages==null) return; for (Message message : ex.responseMessages.getMessage()) { MessageCode is24Code = message.getMessageCode(); String is24Msg = StringUtils.trimToNull( message.getMessage() ); String txt = StringUtils.EMPTY; if (is24Code!=null) txt += is24Code.value(); if (is24Msg!=null) { if (!StringUtils.isBlank( txt )) txt += " | "; txt += is24Msg; } this.putObjectMessage( externalObjectId, code, txt, ex.requestRefNumber ); } } /** * Set the progress of the current export process. * * @param progress * current progress value */ protected final void setProgress( long progress ) { progress = Math.abs( progress ); this.progress = (progress<=this.totalProgress)? progress: this.totalProgress; // launch callback function for progress progressUpdated( this.progress, this.totalProgress ); } /** * Enable / disable removal of objects before update. * * @param removeObjectBeforeUpdate * enabled / disabled */ public void setRemoveObjectBeforeUpdate( boolean removeObjectBeforeUpdate ) { this.removeObjectBeforeUpdate = removeObjectBeforeUpdate; } /** * Enable / disable all values for "energySourceEnev2014". * * @param useNewEnergySourceEnev2014Values * enabled / disabled * * @see notes about Energy Certificate 2014 */ public void setUseNewEnergySourceEnev2014Values( boolean useNewEnergySourceEnev2014Values ) { this.useNewEnergySourceEnev2014Values = useNewEnergySourceEnev2014Values; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy