Package org.socialmusicdiscovery.frontend

Source Code of org.socialmusicdiscovery.frontend.SMDCRUDSearchWindow

/*
*  Copyright 2010-2011, Social Music Discovery project
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions are met:
*      * Redistributions of source code must retain the above copyright
*        notice, this list of conditions and the following disclaimer.
*      * Redistributions in binary form must reproduce the above copyright
*        notice, this list of conditions and the following disclaimer in the
*        documentation and/or other materials provided with the distribution.
*      * Neither the name of Social Music Discovery project nor the
*        names of its contributors may be used to endorse or promote products
*        derived from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
*  DISCLAIMED. IN NO EVENT SHALL SOCIAL MUSIC DISCOVERY PROJECT BE LIABLE FOR ANY
*  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
*  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.socialmusicdiscovery.frontend;

import com.google.inject.Inject;
import com.google.inject.name.Named;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.config.ClientConfig;
import org.apache.pivot.beans.BXML;
import org.apache.pivot.beans.BXMLSerializer;
import org.apache.pivot.beans.Bindable;
import org.apache.pivot.collections.List;
import org.apache.pivot.collections.Sequence;
import org.apache.pivot.serialization.SerializationException;
import org.apache.pivot.util.Resources;
import org.apache.pivot.util.concurrent.Task;
import org.apache.pivot.util.concurrent.TaskExecutionException;
import org.apache.pivot.util.concurrent.TaskListener;
import org.apache.pivot.wtk.*;
import org.socialmusicdiscovery.server.api.OperationStatus;
import org.socialmusicdiscovery.server.api.management.mediaimport.MediaImportStatus;
import org.socialmusicdiscovery.server.business.model.core.Artist;
import org.socialmusicdiscovery.server.business.model.core.Release;
import org.socialmusicdiscovery.server.business.model.core.Work;

import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class SMDCRUDSearchWindow extends Window implements Bindable {
    @Inject
    @Named("smd-server.host")
    private String SMDSERVER;

    @Inject
    @Named("org.socialmusicdiscovery.server.port")
    private String SMDSERVERPORT;

    /**
     * URL to SMD Server application
     */
    private String HOSTURL = null;

    /**
     * Background task for updating progress bar duing media imports
     */
    private Task<Void> importTask = null;
    /**
     * Map with background search tasks currently executing
     */
    private Map<String, Task<Void>> searchTasks = new ConcurrentHashMap<String, Task<Void>>();
    /**
     * Indicates the that import operation has been aborted
     */
    private boolean importAborted = false;

    @BXML
    Meter importProgressMeter;
    @BXML
    Label importProgressDescription;
    @BXML
    ListButton selectedImporterButton;
    @BXML
    PushButton importButton;

    @BXML
    TextInput searchTextInput;
    @BXML
    PushButton searchButton;
    @BXML
    ActivityIndicator searchActivity;

    @BXML
    TableView artistResultsTableView;
    @BXML
    TableView releaseResultsTableView;
    @BXML
    TableView workResultsTableView;

    @BXML
    PushButton closeButton;

    private Resources resources;

    @Inject
    private ClientConfig config;

    @Override
    public void initialize(org.apache.pivot.collections.Map<String, Object> stringObjectMap, URL url, Resources resources) {
        this.resources = resources;
        InjectHelper.injectMembers(this);
        HOSTURL = "http://" + SMDSERVER + ":" + SMDSERVERPORT;
        selectedImporterButton.setSelectedIndex(0);
    }

    @Override
    public void open(Display display, Window owner) {
        super.open(display, owner);

        // Set focus to window
        display.requestFocus();

        // Set focus to search field
        searchTextInput.requestFocus();

        // Check if an import is in progress and refresh the progress bar if it is
        MediaImportStatus status = Client.create(config).resource(HOSTURL + "/mediaimportmodules/" + selectedImporterButton.getSelectedItem()).accept(MediaType.APPLICATION_JSON).get(MediaImportStatus.class);
        if (status != null) {
            startImportProgressBar();
        }

        // Setup listeners for Import/Abort button
        importButton.getButtonPressListeners().add(new ButtonPressListener() {
            @Override
            public void buttonPressed(Button button) {
                if (importTask != null) {
                    abortImport(selectedImporterButton.getSelectedItem().toString());
                } else {
                    startImport(selectedImporterButton.getSelectedItem().toString());
                }
            }
        });

        // Setup listeners for close button
        closeButton.getButtonPressListeners().add(new ButtonPressListener() {
             @Override
             public void buttonPressed(Button button) {
                 getWindow().close();
              }
        });

        // When search button is clicked, we want to search for both artists, releases and works
        searchButton.getButtonPressListeners().add(new ButtonPressListener() {
            @Override
            public void buttonPressed(Button button) {
                searchArtists(searchTextInput.getText(), null, null);
                searchReleases(searchTextInput.getText(), null, null);
                searchWorks(searchTextInput.getText(), null, null);
            }
        });

        // When search field is changed, we want to search for both artists, releases and works
        searchTextInput.getTextInputContentListeners().add(new TextInputContentListener.Adapter() {
            @Override
            public void textChanged(TextInput textInput) {
                if (textInput.getText() != null && textInput.getText().length() > 2) {
                    searchArtists(searchTextInput.getText(), null, null);
                    searchReleases(searchTextInput.getText(), null, null);
                    searchWorks(searchTextInput.getText(), null, null);
                }
            }
        });

        // Selection changes in release results should trigger refresh of artists and works
        releaseResultsTableView.getTableViewSelectionListeners().add(new TableViewSelectionListener.Adapter() {
            @Override
            public void selectedRangesChanged(TableView tableView, Sequence<Span> spanSequence) {
                Release release = (Release) tableView.getSelectedRow();
                if(release!=null) {
                    searchTextInput.setText("");
                    searchArtists(null, null, release.getId());
                    searchWorks(null, null, release.getId());
                }
            }
        });

        // Selection changes in artist results should trigger refresh of releases and works
        artistResultsTableView.getTableViewSelectionListeners().add(new TableViewSelectionListener.Adapter() {
            @Override
            public void selectedRangesChanged(TableView tableView, Sequence<Span> spanSequence) {
                Artist artist = (Artist) tableView.getSelectedRow();
                if(artist!=null) {
                    searchTextInput.setText("");
                    searchReleases(null, artist.getId(), null);
                    searchWorks(null, artist.getId(), null);
                }
            }
        });

        // Selection changes in work results should trigger refresh of artists and releases
        workResultsTableView.getTableViewSelectionListeners().add(new TableViewSelectionListener.Adapter() {
            @Override
            public void selectedRangesChanged(TableView tableView, Sequence<Span> spanSequence) {
                Work work = (Work) tableView.getSelectedRow();
                if(work!=null) {
                    searchTextInput.setText("");
                    searchReleases(null, null, work.getId());
                    searchArtists(null, work.getId(), null);
                }
            }
        });

        // Double click handler for releases
        releaseResultsTableView.getComponentMouseButtonListeners().add(new ComponentMouseButtonListener.Adapter() {
            @Override
            public boolean mouseClick(Component component, Mouse.Button button, int x, int y, int count) {
                try {
                    if (count == 2) {
                        Release release = (Release) releaseResultsTableView.getSelectedRow();
                        BXMLSerializer wtkxSerializer = new BXMLSerializer();
                        EditReleaseWindow window = (EditReleaseWindow) wtkxSerializer.readObject(getClass().getResource("EditReleaseWindow.bxml"),new Resources(resources,EditReleaseWindow.class.getName()));
                        window.open(getDisplay(), getWindow(), release);
                        return true;
                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                } catch (SerializationException e) {
                    throw new RuntimeException(e);
                }
                return false;
            }
        });
        selectedImporterButton.getListButtonSelectionListeners().add(new ListButtonSelectionListener.Adapter() {
            @Override
            public void selectedIndexChanged(ListButton listButton, int i) {
                MediaImportStatus status = Client.create(config).resource(HOSTURL + "/mediaimportmodules/" + selectedImporterButton.getSelectedItem()).accept(MediaType.APPLICATION_JSON).get(MediaImportStatus.class);
                if (status != null) {
                    startImportProgressBar();
                }
            }
        });
    }


    /**
     * Trigger a background search for artists
     *
     * @param name      Partial artist name
     * @param workId    Identity of work
     * @param releaseId Identity of release
     */
    private void searchArtists(String name, String workId, String releaseId) {
        if (searchTasks.containsKey("artist")) {
            return;
        }
        String parameters = "";
        if (name != null && name.length() > 0) {
            try {
                parameters = "?nameContains=" + URLEncoder.encode(name, "UTF8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        } else if (workId != null && workId.length() > 0) {
            try {
                parameters = "?work=" + URLEncoder.encode(workId, "UTF8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        } else if (releaseId != null && releaseId.length() > 0) {
            try {
                parameters = "?release=" + URLEncoder.encode(releaseId, "UTF8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        }
        searchActivity.setVisible(true);
        searchActivity.setActive(true);

        final String searchParameters = parameters;
        searchTasks.put("artist", new Task<Void>() {
            @Override
            public Void execute() throws TaskExecutionException {
                try {
                    Collection<Artist> artists = Client.create(config).resource(HOSTURL + "/artists" + searchParameters).accept(MediaType.APPLICATION_JSON).get(new GenericType<Collection<Artist>>() {
                    });
                    artistResultsTableView.getTableData().clear();
                    for (Artist artist : artists) {
                        ((List<Artist>) artistResultsTableView.getTableData()).add(artist);
                    }
                    return null;
                } catch (Throwable t) {
                    t.printStackTrace();
                    throw new TaskExecutionException(t);
                }
            }
        });
        executeAndCleanupSearch(name, "artist");
    }


    /**
     * Trigger a background search for releases
     *
     * @param name     Partial release name
     * @param artistId Identity of artist
     * @param workId   Identity of work
     */
    private void searchReleases(String name, String artistId, String workId) {
        if (searchTasks.containsKey("release")) {
            return;
        }
        String parameters = "";
        if (name != null && name.length() > 0) {
            try {
                parameters = "?nameContains=" + URLEncoder.encode(name, "UTF8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        } else if (artistId != null && artistId.length() > 0) {
            try {
                parameters = "?artist=" + URLEncoder.encode(artistId, "UTF8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        } else if (workId != null && workId.length() > 0) {
            try {
                parameters = "?work=" + URLEncoder.encode(workId, "UTF8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        }

        searchActivity.setVisible(true);
        searchActivity.setActive(true);

        final String searchParameters = parameters;
        searchTasks.put("release", new Task<Void>() {
            @Override
            public Void execute() throws TaskExecutionException {
                try {
                    Collection<Release> releases = Client.create(config).resource(HOSTURL + "/releases" + searchParameters).accept(MediaType.APPLICATION_JSON).get(new GenericType<Collection<Release>>() {
                    });
                    releaseResultsTableView.getTableData().clear();
                    for (Release release : releases) {
                        ((List<Release>) releaseResultsTableView.getTableData()).add(release);
                    }
                    return null;
                } catch (Throwable t) {
                    t.printStackTrace();
                    throw new TaskExecutionException(t);
                }
            }
        });
        executeAndCleanupSearch(name, "release");
    }

    /**
     * Trigger a background search for works
     *
     * @param name      Partial work name
     * @param artistId  Identity of artist
     * @param releaseId Identity of release
     */
    private void searchWorks(String name, String artistId, String releaseId) {
        if (searchTasks.containsKey("work")) {
            return;
        }
        String parameters = "";
        if (name != null && name.length() > 0) {
            try {
                parameters = "?nameContains=" + URLEncoder.encode(name, "UTF8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        } else if (artistId != null && artistId.length() > 0) {
            try {
                parameters = "?artist=" + URLEncoder.encode(artistId, "UTF8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        } else if (releaseId != null && releaseId.length() > 0) {
            try {
                parameters = "?release=" + URLEncoder.encode(releaseId, "UTF8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        }

        searchActivity.setVisible(true);
        searchActivity.setActive(true);

        final String searchParameters = parameters;
        searchTasks.put("work", new Task<Void>() {
            @Override
            public Void execute() throws TaskExecutionException {
                try {
                    Collection<Work> works = Client.create(config).resource(HOSTURL + "/works" + searchParameters).accept(MediaType.APPLICATION_JSON).get(new GenericType<Collection<Work>>() {
                    });
                    workResultsTableView.getTableData().clear();
                    for (Work work : works) {
                        ((List<Work>) workResultsTableView.getTableData()).add(work);
                    }
                    return null;
                } catch (Throwable t) {
                    t.printStackTrace();
                    throw new TaskExecutionException(t);
                }
            }
        });
        executeAndCleanupSearch(name, "work");
    }

    /**
     * Execute specified search operation as a background thread
     *
     * @param name       The search text used, this is required to make it possible to automatically re-search if user has changed search field during operation
     * @param objectType The type of object to search for
     */
    private void executeAndCleanupSearch(final String name, final String objectType) {
        searchTasks.get(objectType).execute(new TaskAdapter<Void>(new TaskListener<Void>() {
            @Override
            public void taskExecuted(Task<Void> voidTask) {
                searchTasks.remove(objectType);
                if (name != null && !name.equals(searchTextInput.getText()) && searchTextInput.getText().length() > 2) {
                    if (objectType.equals("artist")) {
                        searchArtists(searchTextInput.getText(), null, null);
                    } else if (objectType.equals("release")) {
                        searchReleases(searchTextInput.getText(), null, null);
                    } else if (objectType.equals("work")) {
                        searchWorks(searchTextInput.getText(), null, null);
                    }
                }
                if (searchTasks.isEmpty()) {
                    searchActivity.setVisible(false);
                    searchActivity.setActive(false);
                }
            }

            @Override
            public void executeFailed(Task<Void> voidTask) {
                searchTasks.remove(objectType);
                if (searchTasks.isEmpty()) {
                    searchActivity.setVisible(false);
                    searchActivity.setActive(false);
                }
            }
        }));
    }

    /**
     * Start a media import
     *
     * @param module The import module to use
     */
    private void startImport(String module) {
        if (importTask == null) {
            importAborted = false;
            OperationStatus operationStatus = Client.create(config).resource(HOSTURL + "/mediaimportmodules/" + module).post(OperationStatus.class);
            Boolean status = operationStatus.getSuccess();
            if (status != null && status) {
                startImportProgressBar();
            }
        }
    }

    /**
     * Start a background thread responsible to update the progress bar for an import operation in progress
     *
     */
    private void startImportProgressBar() {
        if (importTask == null) {
            importTask = new Task<Void>() {
                @Override
                public Void execute() throws TaskExecutionException {
                    try {
                        selectedImporterButton.setEnabled(false);
                        importButton.setButtonData(resources.get("abortButton"));
                        importProgressMeter.setPercentage(0);
                        importProgressMeter.setText("");
                        importProgressMeter.setVisible(true);
                        MediaImportStatus status = Client.create(config).resource(HOSTURL + "/mediaimportmodules/" + selectedImporterButton.getSelectedItem().toString()).accept(MediaType.APPLICATION_JSON).get(MediaImportStatus.class);
                        while (status != null && (status.getStatus()==MediaImportStatus.Status.Running || status.getStatus()==MediaImportStatus.Status.Aborting)) {
                            if (status.getTotalNumber() > 0) {
                                importProgressMeter.setPercentage((double) status.getCurrentNumber() / status.getTotalNumber());
                                importProgressMeter.setText(status.getCurrentNumber() + " of " + status.getTotalNumber());
                            }
                            importProgressDescription.setText(status.getCurrentDescription());
                            if(status.getStatus()==MediaImportStatus.Status.Aborting) {
                                importButton.setButtonData(resources.get("abortingButton"));
                                importButton.setEnabled(false);
                            }
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                throw new TaskExecutionException(e);
                            }
                            status = Client.create(config).resource(HOSTURL + "/mediaimportmodules/" + selectedImporterButton.getSelectedItem().toString()).accept(MediaType.APPLICATION_JSON).get(MediaImportStatus.class);
                        }
                        if(status != null && status.getStatus()==MediaImportStatus.Status.Failed) {
                            if (status.getTotalNumber() > 0) {
                                importProgressMeter.setPercentage((double) status.getCurrentNumber() / status.getTotalNumber());
                                importProgressMeter.setText(status.getCurrentNumber() + " of " + status.getTotalNumber());
                            }
                            importProgressDescription.setText("Failed or aborted");
                        }
                    } catch (UniformInterfaceException e) {
                        if (e.getResponse().getStatus() != 204) {
                            throw e;
                        }
                    }
                    return null;
                }
            };
            importTask.execute(new TaskAdapter<Void>(new TaskListener<Void>() {
                @Override
                public void taskExecuted(Task<Void> task) {
                    MediaImportStatus status = Client.create(config).resource(HOSTURL + "/mediaimportmodules/" + selectedImporterButton.getSelectedItem().toString()).accept(MediaType.APPLICATION_JSON).get(MediaImportStatus.class);
                    importProgressMeter.setPercentage(0);
                    if(status!=null && status.getTotalNumber()>0 && status.getStatus()!=MediaImportStatus.Status.FinishedOk) {
                        importProgressMeter.setText(status.getCurrentNumber() + " of " + status.getTotalNumber());
                        importProgressDescription.setText("Failed or aborted");
                    }else {
                        importProgressMeter.setText("");
                        importProgressMeter.setVisible(false);
                        if(status!=null && status.getTotalNumber()>0) {
                            importProgressDescription.setText("Finished");
                        }else {
                            importProgressDescription.setText("");
                        }
                    }
                    importButton.setButtonData(resources.get("importButton"));
                    importButton.setEnabled(true);
                    selectedImporterButton.setEnabled(true);
                    importTask = null;
                }

                @Override
                public void executeFailed(Task<Void> task) {
                    taskExecuted(task);
                }
            }));
        }
    }

    /**
     * Abort an import operation in progress
     *
     * @param module Import module to abort
     */
    public void abortImport(String module) {
        if (importTask != null) {
            importAborted = true;
            Client.create(config).resource(HOSTURL + "/mediaimportmodules/" + module).delete();
        }
    }
}
TOP

Related Classes of org.socialmusicdiscovery.frontend.SMDCRUDSearchWindow

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.