de.metas.ui.web.attachments.DocumentAttachments.java Source code

Java tutorial

Introduction

Here is the source code for de.metas.ui.web.attachments.DocumentAttachments.java

Source

package de.metas.ui.web.attachments;

import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.stream.Stream;

import org.adempiere.archive.api.IArchiveDAO;
import org.adempiere.model.InterfaceWrapperHelper;
import org.adempiere.util.lang.IPair;
import org.adempiere.util.lang.ITableRecordReference;
import org.adempiere.util.lang.ImmutablePair;
import org.compiere.Adempiere;
import org.compiere.model.I_AD_Archive;
import org.compiere.model.I_AD_AttachmentEntry;
import org.compiere.util.Env;
import org.springframework.web.multipart.MultipartFile;

import com.google.common.base.Joiner;
import com.google.common.base.MoreObjects;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.jgoodies.common.base.Objects;

import de.metas.attachments.AttachmentEntry;
import de.metas.attachments.AttachmentEntryId;
import de.metas.attachments.AttachmentEntryService;
import de.metas.ui.web.attachments.json.JSONAttachment;
import de.metas.ui.web.exceptions.EntityNotFoundException;
import de.metas.ui.web.window.datatypes.DocumentId;
import de.metas.ui.web.window.datatypes.DocumentPath;
import de.metas.ui.web.window.descriptor.DetailId;
import de.metas.ui.web.window.descriptor.DocumentEntityDescriptor;
import de.metas.ui.web.window.events.DocumentWebsocketPublisher;
import de.metas.util.Check;
import de.metas.util.Services;
import lombok.Builder;
import lombok.NonNull;

/*
 * #%L
 * metasfresh-webui-api
 * %%
 * Copyright (C) 2017 metas GmbH
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program. If not, see
 * <http://www.gnu.org/licenses/gpl-2.0.html>.
 * #L%
 */

/**
 * Document attachments facade.
 *
 * NOTE to developers: introduced to hide behind legacy attachments code.
 *
 * @author metas-dev <dev@metasfresh.com>
 *
 */
final class DocumentAttachments {
    public static final String ID_PREFIX_Attachment = "ATT";
    public static final String ID_PREFIX_Archive = "ARR";
    private static final String ID_SEPARATOR = "_";
    private static final Splitter ID_Splitter = Splitter.on(ID_SEPARATOR);
    private static final Joiner ID_Joiner = Joiner.on(ID_SEPARATOR);

    private final transient AttachmentEntryService attachmentEntryService = Adempiere
            .getBean(AttachmentEntryService.class);

    private final DocumentPath documentPath;
    private final ITableRecordReference recordRef;
    private final DocumentEntityDescriptor entityDescriptor;
    private final DocumentWebsocketPublisher websocketPublisher;

    @Builder
    private DocumentAttachments(@NonNull final DocumentPath documentPath,
            @NonNull final ITableRecordReference recordRef,
            @NonNull final DocumentEntityDescriptor entityDescriptor,
            @NonNull final DocumentWebsocketPublisher websocketPublisher) {
        this.documentPath = documentPath;
        this.recordRef = recordRef;
        this.entityDescriptor = entityDescriptor;
        this.websocketPublisher = websocketPublisher;
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this).addValue(recordRef).toString();
    }

    public List<JSONAttachment> toJson() {
        final Stream<IDocumentAttachmentEntry> attachments = attachmentEntryService.getByReferencedRecord(recordRef)
                .stream().map(entry -> DocumentAttachmentEntry
                        .of(buildId(ID_PREFIX_Attachment, entry.getId().getRepoId()), entry));

        final Stream<DocumentArchiveEntry> archives = Services.get(IArchiveDAO.class)
                .retrieveLastArchives(Env.getCtx(), recordRef, 10).stream().map(archive -> DocumentArchiveEntry
                        .of(buildId(ID_PREFIX_Archive, archive.getAD_Archive_ID()), archive));

        return Stream.concat(attachments, archives).map(JSONAttachment::of)
                .collect(ImmutableList.toImmutableList());
    }

    public void addEntry(final MultipartFile file) throws IOException {
        Check.assumeNotNull(file, "Parameter file is not null");
        final String name = file.getOriginalFilename();
        final byte[] data = file.getBytes();

        attachmentEntryService.createNewAttachment(recordRef, name, data);

        notifyRelatedDocumentTabsChanged();
    }

    public void addURLEntry(final String name, final URI url) {
        attachmentEntryService.createNewAttachment(recordRef, name, url);

        notifyRelatedDocumentTabsChanged();
    }

    public IDocumentAttachmentEntry getEntry(final DocumentId id) {
        final IPair<String, Integer> prefixAndId = toPrefixAndEntryId(id);
        final String idPrefix = prefixAndId.getLeft();
        final int entryId = prefixAndId.getRight();

        if (ID_PREFIX_Attachment.equals(idPrefix)) {
            final AttachmentEntry entry = attachmentEntryService.getById(AttachmentEntryId.ofRepoId(entryId));
            if (entry == null) {
                throw new EntityNotFoundException(id.toJson());
            }
            return DocumentAttachmentEntry.of(id, entry);
        } else if (ID_PREFIX_Archive.equals(idPrefix)) {
            final I_AD_Archive archive = Services.get(IArchiveDAO.class).retrieveArchiveOrNull(Env.getCtx(),
                    recordRef, entryId);
            if (archive == null) {
                throw new EntityNotFoundException(id.toJson());
            }
            return DocumentArchiveEntry.of(id, archive);
        } else {
            throw new EntityNotFoundException(id.toJson());
        }
    }

    public void deleteEntry(final DocumentId id) {
        final IPair<String, Integer> prefixAndId = toPrefixAndEntryId(id);
        final String idPrefix = prefixAndId.getLeft();
        final int entryId = prefixAndId.getRight();

        if (ID_PREFIX_Attachment.equals(idPrefix)) {
            final AttachmentEntry entry = attachmentEntryService.getById(AttachmentEntryId.ofRepoId(entryId));
            attachmentEntryService.unattach(recordRef, entry);

            notifyRelatedDocumentTabsChanged();
        } else if (ID_PREFIX_Archive.equals(idPrefix)) {
            final I_AD_Archive archive = Services.get(IArchiveDAO.class).retrieveArchiveOrNull(Env.getCtx(),
                    recordRef, entryId);
            if (archive == null) {
                throw new EntityNotFoundException(id.toJson());
            }
            InterfaceWrapperHelper.delete(archive);
        } else {
            throw new EntityNotFoundException(id.toJson());
        }
    }

    private static IPair<String, Integer> toPrefixAndEntryId(final DocumentId id) {
        final List<String> idParts = ID_Splitter.splitToList(id.toJson());
        if (idParts.size() != 2) {
            throw new IllegalArgumentException("Invalid attachment ID");
        }

        final String idPrefix = idParts.get(0);
        final int entryId = Integer.parseInt(idParts.get(1));

        return ImmutablePair.of(idPrefix, entryId);
    }

    private static final DocumentId buildId(final String idPrefix, final int id) {
        return DocumentId.ofString(ID_Joiner.join(idPrefix, id));
    }

    /**
     * If the document contains some attachment related tabs, it will send an "stale" notification to frontend.
     * In this way, frontend will be aware of this and will have to refresh the tab.
     */
    private void notifyRelatedDocumentTabsChanged() {
        final ImmutableSet<DetailId> attachmentRelatedTabIds = entityDescriptor.getIncludedEntities().stream()
                .filter(includedEntityDescriptor -> Objects.equals(includedEntityDescriptor.getTableNameOrNull(),
                        I_AD_AttachmentEntry.Table_Name))
                .map(includedEntityDescriptor -> includedEntityDescriptor.getDetailId())
                .collect(ImmutableSet.toImmutableSet());
        if (attachmentRelatedTabIds.isEmpty()) {
            return;
        }

        websocketPublisher.staleTabs(documentPath.getWindowId(), documentPath.getDocumentId(),
                attachmentRelatedTabIds);
    }

}