diff --git a/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/CalvalusPortal.java b/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/CalvalusPortal.java index 72e7e0036..62f23bb26 100644 --- a/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/CalvalusPortal.java +++ b/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/CalvalusPortal.java @@ -11,6 +11,7 @@ import com.bc.calvalus.portal.shared.ContextRetrievalServiceAsync; import com.bc.calvalus.portal.shared.DtoAggregatorDescriptor; import com.bc.calvalus.portal.shared.DtoCalvalusConfig; +import com.bc.calvalus.portal.shared.DtoColorPalette; import com.bc.calvalus.portal.shared.DtoProcessorDescriptor; import com.bc.calvalus.portal.shared.DtoProductSet; import com.bc.calvalus.portal.shared.DtoProduction; @@ -60,6 +61,7 @@ public class CalvalusPortal implements EntryPoint, PortalContext { "vicariousCalibrationView", "matchupComparisonView", "l2ToL3ComparisonView", + "qlView", "regionsView", "requestsView", "bundlesView", @@ -74,6 +76,7 @@ public class CalvalusPortal implements EntryPoint, PortalContext { // Data provided by various external services private ListDataProvider regions; private DtoProductSet[] productSets; + private DtoColorPalette[] colorPalettes; private DtoProcessorDescriptor[] systemProcessors; private DtoProcessorDescriptor[] userProcessors; private DtoProcessorDescriptor[] allUserProcessors; @@ -128,6 +131,7 @@ public void onModuleLoad() { Runnable runnable = new Runnable() { public void run() { backendService.loadRegions(NO_FILTER, new InitRegionsCallback()); + backendService.loadColorPalettes(NO_FILTER, new InitColorPaletteSetsCallback()); backendService.getProductSets(NO_FILTER, new InitProductSetsCallback()); final BundleFilter systemFilter = new BundleFilter(); @@ -182,6 +186,11 @@ public DtoProductSet[] getProductSets() { return productSets; } + @Override + public DtoColorPalette[] getColorPalettes() { + return colorPalettes; + } + @Override public DtoProcessorDescriptor[] getProcessors(String filter) { if (filter.equals(BundleFilter.PROVIDER_SYSTEM)) { @@ -285,6 +294,8 @@ private PortalView createViewOf(String name) { return new OrderMACProductionView(this); case "l2ToL3ComparisonView": return new OrderL2toL3ProductionView(this); + case "qlView": + return new OrderQLProductionView(this); case "regionsView": return new ManageRegionsView(this); case "bundlesView": @@ -482,6 +493,22 @@ public void onFailure(Throwable caught) { } } + private class InitColorPaletteSetsCallback implements AsyncCallback { + + @Override + public void onSuccess(DtoColorPalette[] dtoColorPalettes) { + CalvalusPortal.this.colorPalettes = dtoColorPalettes; + maybeInitFrontend(); + } + + @Override + public void onFailure(Throwable caught) { + caught.printStackTrace(System.err); + Dialog.error("Server-side Error", caught.getMessage()); + CalvalusPortal.this.colorPalettes = new DtoColorPalette[0]; + } + } + private class InitProcessorsCallback implements AsyncCallback { private final String filter; diff --git a/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/OrderL2ProductionView.java b/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/OrderL2ProductionView.java index e1bb9f9d8..970009328 100644 --- a/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/OrderL2ProductionView.java +++ b/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/OrderL2ProductionView.java @@ -18,6 +18,7 @@ import com.bc.calvalus.portal.shared.DtoInputSelection; import com.bc.calvalus.portal.shared.DtoProcessorDescriptor; +import com.bc.calvalus.portal.shared.DtoProcessorVariable; import com.google.gwt.core.client.Scheduler; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Anchor; @@ -44,6 +45,7 @@ public class OrderL2ProductionView extends OrderProductionView { private ProductsFromCatalogueForm productsFromCatalogueForm; private L2ConfigForm l2ConfigForm; private OutputParametersForm outputParametersForm; + private QuicklookParametersForm quicklookParametersForm; private Widget widget; public OrderL2ProductionView(PortalContext portalContext) { @@ -77,6 +79,7 @@ public void onClearSelectionClick() { } outputParametersForm = new OutputParametersForm(portalContext); + quicklookParametersForm = new QuicklookParametersForm(portalContext); l2ConfigForm.setProductSet(productSetSelectionForm.getSelectedProductSet()); handleProcessorChanged(); @@ -89,6 +92,7 @@ public void onClearSelectionClick() { } panel.add(l2ConfigForm); panel.add(outputParametersForm); + panel.add(quicklookParametersForm); Anchor l2Help = new Anchor("Show Help"); l2Help.getElement().getStyle().setProperty("textDecoration", "none"); l2Help.addStyleName("anchor"); @@ -168,6 +172,7 @@ protected HashMap getProductionParameters() { } parameters.putAll(l2ConfigForm.getValueMap()); parameters.putAll(outputParametersForm.getValueMap()); + parameters.putAll(quicklookParametersForm.getValueMap()); return parameters; } @@ -185,6 +190,7 @@ public void setProductionParameters(Map parameters) { } l2ConfigForm.setValues(parameters); outputParametersForm.setValues(parameters); + quicklookParametersForm.setValues(parameters); } private class InputSelectionCallback implements AsyncCallback { @@ -216,6 +222,13 @@ private void handleProcessorChanged() { add("BigGeoTiff", outputFormats); } outputParametersForm.setAvailableOutputFormats(outputFormats.toArray(new String[0])); + + List processorVariables = new ArrayList<>(); + DtoProcessorVariable[] dtoProcessorVariables = processorDescriptor.getProcessorVariables(); + for (DtoProcessorVariable dtoProcessorVariable : dtoProcessorVariables) { + processorVariables.add(dtoProcessorVariable.getName()); + } + quicklookParametersForm.setBandNames(processorVariables.toArray(new String[0])); } } @@ -224,4 +237,4 @@ private static void add(String format, List outputFormats) { outputFormats.add(format); } } -} \ No newline at end of file +} diff --git a/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/OrderQLProductionView.java b/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/OrderQLProductionView.java new file mode 100644 index 000000000..af0f49b52 --- /dev/null +++ b/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/OrderQLProductionView.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2013 Brockmann Consult GmbH (info@brockmann-consult.de) + * + * 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 3 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/ + */ + +package com.bc.calvalus.portal.client; + +import com.bc.calvalus.portal.shared.DtoInputSelection; +import com.bc.calvalus.portal.shared.DtoProcessorDescriptor; +import com.bc.calvalus.portal.shared.DtoProcessorVariable; +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Anchor; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwt.user.client.ui.Widget; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Demo view that lets users submit a new L2 production. + * + * @author Norman + */ +public class OrderQLProductionView extends OrderProductionView { + + public static final String ID = OrderQLProductionView.class.getName(); + + private ProductSetSelectionForm productSetSelectionForm; + private ProductSetFilterForm productSetFilterForm; + private ProductsFromCatalogueForm productsFromCatalogueForm; + private OutputParametersForm outputParametersForm; + private QuicklookParametersForm quicklookParametersForm; + private Widget widget; + + public OrderQLProductionView(PortalContext portalContext) { + super(portalContext); + + productSetSelectionForm = new ProductSetSelectionForm(getPortal()); + productSetFilterForm = new ProductSetFilterForm(portalContext); + productSetFilterForm.setProductSet(productSetSelectionForm.getSelectedProductSet()); + + if (getPortal().withPortalFeature(INPUT_FILES_PANEL)) { + productsFromCatalogueForm = new ProductsFromCatalogueForm(getPortal()); + productsFromCatalogueForm.addInputSelectionHandler(new ProductsFromCatalogueForm.InputSelectionHandler() { + @Override + public AsyncCallback getInputSelectionChangedCallback() { + return new InputSelectionCallback(); + } + + @Override + public void onClearSelectionClick() { + productsFromCatalogueForm.removeSelections(); + } + }); + } + + outputParametersForm = new OutputParametersForm(portalContext); + outputParametersForm.showFormatSelectionPanel(false); + outputParametersForm.setAvailableOutputFormats("Image"); + + quicklookParametersForm = new QuicklookParametersForm(portalContext); + quicklookParametersForm.setBandNames(); + + VerticalPanel panel = new VerticalPanel(); + panel.setWidth("100%"); + panel.add(productSetSelectionForm); + panel.add(productSetFilterForm); + if (getPortal().withPortalFeature(INPUT_FILES_PANEL)){ + panel.add(productsFromCatalogueForm); + } + panel.add(outputParametersForm); + panel.add(quicklookParametersForm); + Anchor l2Help = new Anchor("Show Help"); + l2Help.getElement().getStyle().setProperty("textDecoration", "none"); + l2Help.addStyleName("anchor"); + panel.add(l2Help); + HelpSystem.addClickHandler(l2Help, "l2Processing"); + //panel.add(new HTML("
")); + panel.add(createOrderPanel()); + + this.widget = panel; + } + + @Override + public Widget asWidget() { + return widget; + } + + @Override + public String getViewId() { + return ID; + } + + @Override + public String getTitle() { + return "Quicklook generation"; + } + + @Override + protected String getProductionType() { + return "QL"; + } + + @Override + public void onShowing() { + // make sure #triggerResize is called after the new view is shown + Scheduler.get().scheduleFinally(() -> { + // See http://code.google.com/p/gwt-google-apis/issues/detail?id=127 + productSetFilterForm.getRegionMap().getMapWidget().triggerResize(); + }); + } + + @Override + protected boolean validateForm() { + try { + productSetSelectionForm.validateForm(); + productSetFilterForm.validateForm(); + if (productsFromCatalogueForm != null) { + productsFromCatalogueForm.validateForm(productSetSelectionForm.getSelectedProductSet().getName()); + } + outputParametersForm.validateForm(); + + + if (!getPortal().withPortalFeature("unlimitedJobSize")) { + try { + final int numDaysValue = Integer.parseInt(productSetFilterForm.numDays.getValue()); + if (numDaysValue > 365 + 366) { + throw new ValidationException(productSetFilterForm.numDays, "time range larger than allowed"); + } + } catch (NumberFormatException e) { + // ignore + } + } + return true; + } catch (ValidationException e) { + e.handle(); + return false; + } + } + + @Override + protected HashMap getProductionParameters() { + HashMap parameters = new HashMap<>(); + parameters.putAll(productSetSelectionForm.getValueMap()); + parameters.putAll(productSetFilterForm.getValueMap()); + if (productsFromCatalogueForm != null) { + parameters.putAll(productsFromCatalogueForm.getValueMap()); + } + parameters.putAll(outputParametersForm.getValueMap()); + parameters.putAll(quicklookParametersForm.getValueMap()); + return parameters; + } + + @Override + public boolean isRestoringRequestPossible() { + return true; + } + + @Override + public void setProductionParameters(Map parameters) { + productSetSelectionForm.setValues(parameters); + productSetFilterForm.setValues(parameters); + if (productsFromCatalogueForm != null) { + productsFromCatalogueForm.setValues(parameters); + } + outputParametersForm.setValues(parameters); + quicklookParametersForm.setValues(parameters); + } + + private class InputSelectionCallback implements AsyncCallback { + + @Override + public void onSuccess(DtoInputSelection inputSelection) { + Map inputSelectionMap = UIUtils.parseParametersFromContext(inputSelection); + productsFromCatalogueForm.setValues(inputSelectionMap); + productSetSelectionForm.setValues(inputSelectionMap); + productSetFilterForm.setValues(inputSelectionMap); + } + + @Override + public void onFailure(Throwable caught) { + Dialog.error("Error in retrieving input selection", caught.getMessage()); + } + } +} diff --git a/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/PortalContext.java b/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/PortalContext.java index 9cdd74dbd..5ec3eb96e 100644 --- a/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/PortalContext.java +++ b/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/PortalContext.java @@ -5,6 +5,7 @@ import com.bc.calvalus.portal.shared.BackendServiceAsync; import com.bc.calvalus.portal.shared.ContextRetrievalServiceAsync; import com.bc.calvalus.portal.shared.DtoAggregatorDescriptor; +import com.bc.calvalus.portal.shared.DtoColorPalette; import com.bc.calvalus.portal.shared.DtoProcessorDescriptor; import com.bc.calvalus.portal.shared.DtoProductSet; import com.bc.calvalus.portal.shared.DtoProduction; @@ -27,6 +28,8 @@ public interface PortalContext { // make this return ListDataProvider DtoProductSet[] getProductSets(); + DtoColorPalette[] getColorPalettes(); + // make this return ListDataProvider DtoProcessorDescriptor[] getProcessors(String filter); DtoAggregatorDescriptor[] getAggregators(String filter); diff --git a/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/QuicklookParametersForm.java b/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/QuicklookParametersForm.java new file mode 100755 index 000000000..4b639136b --- /dev/null +++ b/calvalus-portal/src/main/java/com/bc/calvalus/portal/client/QuicklookParametersForm.java @@ -0,0 +1,711 @@ +/* + * Copyright (C) 2018 Brockmann Consult GmbH (info@brockmann-consult.de) + * + * 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 3 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/ + */ + +package com.bc.calvalus.portal.client; + +import com.bc.calvalus.portal.shared.DtoColorPalette; +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.Style; +import com.google.gwt.event.dom.client.ChangeEvent; +import com.google.gwt.event.dom.client.ChangeHandler; +import com.google.gwt.event.logical.shared.ValueChangeEvent; +import com.google.gwt.event.logical.shared.ValueChangeHandler; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.ui.CheckBox; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HTMLPanel; +import com.google.gwt.user.client.ui.IntegerBox; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.ListBox; +import com.google.gwt.user.client.ui.RadioButton; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; +import com.google.gwt.xml.client.Document; +import com.google.gwt.xml.client.Node; +import com.google.gwt.xml.client.NodeList; +import com.google.gwt.xml.client.XMLParser; + +import java.util.HashMap; +import java.util.Map; + +/** + * This form is used regarding visualisations settings. + * + * @author Declan + */ +public class QuicklookParametersForm extends Composite { + + interface TheUiBinder extends UiBinder { + } + + private static TheUiBinder uiBinder = GWT.create(TheUiBinder.class); + + private static int instanceCounter = 0; + private int radioGroupId = 0; + + private static final String CUSTOM_BAND = ""; + + private static final String BANDNAME_LISTBOX_ROW = "bandNameListBoxRow"; + + private final PortalContext portal; + + @UiField + HTMLPanel singleBandPanel; + @UiField + HTMLPanel multiBandPanel; + @UiField + HTMLPanel moreOptionsPanel; + @UiField + HTMLPanel geoServerPanel; + + @UiField + RadioButton quicklookNone; + @UiField + RadioButton quicklookSingleBand; + @UiField + RadioButton quicklookMultiBand; + + @UiField + ListBox bandNameListBox; + @UiField + Label bandNameRowLabel; + @UiField + TextBox bandName; + @UiField + ListBox colorPalette; + + @UiField + TextBox rgbaExpressionsRedBand; + @UiField + TextBox rgbaExpressionsGreenBand; + @UiField + TextBox rgbaExpressionsBlueBand; + @UiField + TextBox rgbaExpressionsAlphaBand; + @UiField + TextBox rgbaMinSamples; + @UiField + TextBox rgbaMaxSamples; + + @UiField + ListBox imageType; + @UiField + TextBox overlayURL; + @UiField + TextBox maskOverlays; + @UiField + IntegerBox subSamplingX; + @UiField + IntegerBox subSamplingY; + @UiField + TextBox backgroundColor; + @UiField + CheckBox legendEnabled; + + @UiField + TextBox geoServerRestUrl; + @UiField + TextBox geoServerUsername; + @UiField + TextBox geoServerPassword; + @UiField + TextBox geoServerWorkspace; + @UiField + TextBox geoServerStore; + @UiField + TextBox geoServerLayer; + @UiField + TextBox geoServerStyle; + + private DtoColorPalette[] availableColorPalettes = null; + private Boolean pageLoaded = false; + private String[] availableBandNames = null; + + public QuicklookParametersForm(PortalContext portalContext) { + this.portal = portalContext; + + initWidget(uiBinder.createAndBindUi(this)); + + instanceCounter++; + radioGroupId = instanceCounter; + + //give radio group a unique name for each instance + quicklookNone.setName("quicklookSelection" + radioGroupId); + quicklookSingleBand.setName("quicklookSelection" + radioGroupId); + quicklookMultiBand.setName("quicklookSelection" + radioGroupId); + + quicklookNone.addValueChangeHandler(new ValueChangeHandler() { + @Override + public void onValueChange(ValueChangeEvent event) { + if (event.getValue()) + quicklookNoneChangeHandler(); + } + }); + + quicklookSingleBand.addValueChangeHandler(new ValueChangeHandler() { + @Override + public void onValueChange(ValueChangeEvent event) { + if (event.getValue()) + quicklookSingleBandChangeHandler(); + } + }); + + quicklookMultiBand.addValueChangeHandler(new ValueChangeHandler() { + @Override + public void onValueChange(ValueChangeEvent event) { + if (event.getValue()) + quicklookMultiBandChangeHandler(); + } + }); + + bandName.addValueChangeHandler(new ValueChangeHandler() { + @Override + public void onValueChange(ValueChangeEvent event) { + bandNameChangeHandler(); + } + }); + + bandNameListBox.addChangeHandler(new ChangeHandler() { + @Override + public void onChange(ChangeEvent event) { + bandNameListBoxChangeHandler(); + } + }); + + setAvailableImageTypes(); + setColorPalettes(); + } + + @Override + protected void onLoad() { + //give HTML element a unique id for each instance + Element element = DOM.getElementById(BANDNAME_LISTBOX_ROW); + element.setId(BANDNAME_LISTBOX_ROW + radioGroupId); + + this.pageLoaded = true; + quicklookNone.setValue(true, true); + buildBandNameListBox(); + } + + private void bandNameChangeHandler() { + // band name field changed, reset list box index and call it's handler + int itemCount = bandNameListBox.getItemCount(); + String bandNameValue = bandName.getValue(); + bandNameListBox.setSelectedIndex(0); + for (int i = 0; i < itemCount; i++) { + String listBand = bandNameListBox.getValue(i); + if (listBand != null && listBand.equals(bandNameValue)) { + bandNameListBox.setSelectedIndex(i); + break; + } + } + bandNameListBoxChangeHandler(); + } + + private void bandNameListBoxChangeHandler() { + if (!pageLoaded) + return; + + int selectedIndex = bandNameListBox.getSelectedIndex(); + Element element = DOM.getElementById(BANDNAME_LISTBOX_ROW + radioGroupId); + if (!quicklookSingleBand.getValue() || selectedIndex < 0) { + // single band not selected OR no values in listbox + // enable bandName textbox, make drop down list invisible + bandNameRowLabel.setText("Band name:"); + bandName.setEnabled(true); + if (element != null) + element.getStyle().setDisplay(Style.Display.NONE); + } else { + // single band is selected AND values in listbox + // make drop down list visible + if (element != null) + element.getStyle().setDisplay(Style.Display.TABLE_ROW); + bandNameRowLabel.setText(""); + if (selectedIndex == 0) { + // custom band name option selected + // enable bandName textbox + bandName.setEnabled(true); + } else if (selectedIndex > 0) { + // band name (sourced from processor) selected + // disable bandName textbox + bandName.setValue(bandNameListBox.getValue(selectedIndex)); + bandName.setEnabled(false); + } + } + } + + private void quicklookNoneChangeHandler() { + singleBandPanel.setVisible(false); + multiBandPanel.setVisible(false); + moreOptionsPanel.setVisible(false); + geoServerPanel.setVisible(false); + } + + private void quicklookSingleBandChangeHandler() { + singleBandPanel.setVisible(true); + multiBandPanel.setVisible(false); + moreOptionsPanel.setVisible(true); + geoServerPanel.setVisible(true); + bandNameChangeHandler(); + } + + private void quicklookMultiBandChangeHandler() { + singleBandPanel.setVisible(false); + multiBandPanel.setVisible(true); + moreOptionsPanel.setVisible(true); + geoServerPanel.setVisible(true); + } + + public void setAvailableImageTypes() { + String[] imageNames = {"jpeg", "png", "tiff", "geotiff"}; + int selectedIndex = imageType.getSelectedIndex(); + imageType.clear(); + for (String imageName : imageNames) { + imageType.addItem(imageName); + } + if (selectedIndex >= 0 && selectedIndex < imageNames.length) { + imageType.setSelectedIndex(selectedIndex); + } else { + imageType.setSelectedIndex(0); + } + } + + private void setColorPalettes() { + this.availableColorPalettes = portal.getColorPalettes(); + colorPalette.clear(); + colorPalette.addItem(""); + for (DtoColorPalette dtoColorPalette : this.availableColorPalettes) { + colorPalette.addItem(dtoColorPalette.getQualifiedName(), dtoColorPalette.getCpdURL()); + } + colorPalette.setSelectedIndex(0); + } + + public void setBandNames(String... bandNames) { + this.availableBandNames = bandNames; + buildBandNameListBox(); + } + + private void buildBandNameListBox() { + bandNameListBox.clear(); + if (!pageLoaded) + return; + + if (availableBandNames != null && availableBandNames.length > 0) { + bandNameListBox.addItem(CUSTOM_BAND); + bandNameListBox.setSelectedIndex(0); + for (String bandName : this.availableBandNames) { + bandNameListBox.addItem(bandName); + } + } + bandNameChangeHandler(); + } + + public Map getValueMap() { + Map parameters = new HashMap(); + if (quicklookNone.getValue()) { + return parameters; + } + + String indentXML = " "; + + // imageType + String imageTypeXML = indentXML + "" + imageType.getSelectedValue() + "\n"; + + // overlayURL + String overlayURLValue = overlayURL.getValue(); + String overlayURLXML = ""; + if (overlayURLValue != null && !overlayURLValue.isEmpty()) { + overlayURLXML = indentXML + "" + overlayURLValue + "\n"; + } + + // maskOverlays + String maskOverlaysValue = maskOverlays.getValue(); + String maskOverlaysXML = ""; + if (maskOverlaysValue != null && !maskOverlaysValue.isEmpty()) { + maskOverlaysXML = indentXML + "" + maskOverlaysValue + "\n"; + } + + // subSamplingX + Integer subSamplingXValue = subSamplingX.getValue(); + String subSamplingXXML = ""; + if (subSamplingXValue != null && subSamplingXValue >= 1) { + subSamplingXXML = indentXML + "" + subSamplingXValue + "\n"; + } + + // subSamplingY + Integer subSamplingYValue = subSamplingY.getValue(); + String subSamplingYXML = ""; + if (subSamplingYValue != null && subSamplingYValue >= 1) { + subSamplingYXML = indentXML + "" + subSamplingYValue + "\n"; + } + + // backgroundColor + String backgroundColorValue = backgroundColor.getValue(); + String backgroundColorXML = ""; + if (backgroundColorValue != null && !backgroundColorValue.isEmpty()) { + backgroundColorXML = indentXML + "" + backgroundColorValue + "\n"; + } + + // legendEnabled + Boolean legendEnabledValue = legendEnabled.getValue(); + String legendEnabledXML = ""; + if (legendEnabledValue) { + legendEnabledXML = indentXML + "true\n"; + } + + // GeoServer section... + // geoServerRestUrl + String geoServerRestUrlValue = geoServerRestUrl.getValue(); + String geoServerRestUrlXML = ""; + if (geoServerRestUrlValue != null && !geoServerRestUrlValue.isEmpty()) { + geoServerRestUrlXML = indentXML + "" + geoServerRestUrlValue + "\n"; + } + + // geoServerUsername + String geoServerUsernameValue = geoServerUsername.getValue(); + String geoServerUsernameXML = ""; + if (geoServerUsernameValue != null && !geoServerUsernameValue.isEmpty()) { + geoServerUsernameXML = indentXML + "" + geoServerUsernameValue + "\n"; + } + + // geoServerPassword + String geoServerPasswordValue = geoServerPassword.getValue(); + String geoServerPasswordXML = ""; + if (geoServerPasswordValue != null && !geoServerPasswordValue.isEmpty()) { + geoServerPasswordXML = indentXML + "" + geoServerPasswordValue + "\n"; + } + + // geoServerWorkspace + String geoServerWorkspaceValue = geoServerWorkspace.getValue(); + String geoServerWorkspaceXML = ""; + if (geoServerWorkspaceValue != null && !geoServerWorkspaceValue.isEmpty()) { + geoServerWorkspaceXML = indentXML + "" + geoServerWorkspaceValue + "\n"; + } + + // geoServerStore + String geoServerStoreValue = geoServerStore.getValue(); + String geoServerStoreXML = ""; + if (geoServerStoreValue != null && !geoServerStoreValue.isEmpty()) { + geoServerStoreXML = indentXML + "" + geoServerStoreValue + "\n"; + } + + // geoServerLayer + String geoServerLayerValue = geoServerLayer.getValue(); + String geoServerLayerXML = ""; + if (geoServerLayerValue != null && !geoServerLayerValue.isEmpty()) { + geoServerLayerXML = indentXML + "" + geoServerLayerValue + "\n"; + } + + // geoServerStyle + String geoServerStyleValue = geoServerStyle.getValue(); + String geoServerStyleXML = ""; + if (geoServerStyleValue != null && !geoServerStyleValue.isEmpty()) { + geoServerStyleXML = indentXML + "" + geoServerStyleValue + "\n"; + } + + String quicklookParameters = ""; + if (quicklookSingleBand.getValue()) { + + // bandName + String bandNameXML = ""; + String bandNameValue = bandName.getValue(); + if (bandNameValue != null && !bandNameValue.isEmpty()) { + bandNameXML = indentXML + "" + bandNameValue + "\n"; + } + + // color palette + String cpdURLXML = ""; + String colorPaletteValue = colorPalette.getSelectedValue(); + if (colorPaletteValue != null && !colorPaletteValue.isEmpty()) { + cpdURLXML = indentXML + "" + colorPaletteValue + "\n"; + } + + quicklookParameters = "\n" + + " \n" + + " \n" + + bandNameXML + + cpdURLXML + + imageTypeXML + + overlayURLXML + + maskOverlaysXML + + subSamplingXXML + + subSamplingYXML + + backgroundColorXML + + legendEnabledXML + + geoServerRestUrlXML + + geoServerUsernameXML + + geoServerPasswordXML + + geoServerWorkspaceXML + + geoServerStoreXML + + geoServerLayerXML + + geoServerStyleXML + + " \n" + + " \n" + + ""; + } else if (quicklookMultiBand.getValue()) { + + // RGBAExpressions + String rgbaExpressionsXML = ""; + String rgbaExpressionsRedBandValue = rgbaExpressionsRedBand.getValue(); + String rgbaExpressionsGreenBandValue = rgbaExpressionsGreenBand.getValue(); + String rgbaExpressionsBlueBandValue = rgbaExpressionsBlueBand.getValue(); + String rgbaExpressionsAlphaBandValue = rgbaExpressionsAlphaBand.getValue(); + + if (rgbaExpressionsRedBandValue != null && !rgbaExpressionsRedBandValue.isEmpty() && + rgbaExpressionsGreenBandValue != null && !rgbaExpressionsGreenBandValue.isEmpty() && + rgbaExpressionsBlueBandValue != null && !rgbaExpressionsBlueBandValue.isEmpty()) { + + rgbaExpressionsXML = indentXML + "" + + rgbaExpressionsRedBandValue + "," + + rgbaExpressionsGreenBandValue + "," + + rgbaExpressionsBlueBandValue; + + if (rgbaExpressionsAlphaBandValue != null && !rgbaExpressionsAlphaBandValue.isEmpty()) + rgbaExpressionsXML = rgbaExpressionsXML + "," + rgbaExpressionsAlphaBandValue; + + rgbaExpressionsXML = rgbaExpressionsXML + "\n"; + } + + // rgbaMinSamples + String rgbaMinSamplesXML = ""; + String rgbaMinSamplesValue = rgbaMinSamples.getValue(); + if (rgbaMinSamplesValue != null && !rgbaMinSamplesValue.isEmpty()) { + rgbaMinSamplesXML = indentXML + "" + rgbaMinSamplesValue + "\n"; + } + + // rgbaMaxSamples + String rgbaMaxSamplesXML = ""; + String rgbaMaxSamplesValue = rgbaMaxSamples.getValue(); + if (rgbaMaxSamplesValue != null && !rgbaMaxSamplesValue.isEmpty()) { + rgbaMaxSamplesXML = indentXML + "" + rgbaMaxSamplesValue + "\n"; + } + + quicklookParameters = "\n" + + " \n" + + " \n" + + rgbaExpressionsXML + + rgbaMinSamplesXML + + rgbaMaxSamplesXML + + imageTypeXML + + overlayURLXML + + maskOverlaysXML + + subSamplingXXML + + subSamplingYXML + + backgroundColorXML + + legendEnabledXML + + geoServerRestUrlXML + + geoServerUsernameXML + + geoServerPasswordXML + + geoServerWorkspaceXML + + geoServerStoreXML + + geoServerLayerXML + + geoServerStyleXML + + " \n" + + " \n" + + ""; + } + + if (!quicklookParameters.isEmpty()) { + parameters.put("quicklooks", "true"); + parameters.put("calvalus.ql.parameters", quicklookParameters); + } + + return parameters; + } + + public void setValues(Map parameters) { + String quicklookParametersValue = parameters.get("calvalus.ql.parameters"); + if (quicklookParametersValue == null || quicklookParametersValue.isEmpty()) { + + bandName.setValue(null); + colorPalette.setSelectedIndex(0); + + rgbaExpressionsRedBand.setValue(null); + rgbaExpressionsGreenBand.setValue(null); + rgbaExpressionsBlueBand.setValue(null); + rgbaExpressionsAlphaBand.setValue(null); + rgbaMinSamples.setValue(null); + rgbaMaxSamples.setValue(null); + + imageType.setSelectedIndex(0); + overlayURL.setValue(null); + maskOverlays.setValue(null); + subSamplingX.setValue(null); + maskOverlays.setValue(null); + legendEnabled.setValue(false); + + geoServerRestUrl.setValue(null); + geoServerUsername.setValue(null); + geoServerPassword.setValue(null); + geoServerWorkspace.setValue(null); + geoServerStore.setValue(null); + geoServerLayer.setValue(null); + geoServerStyle.setValue(null); + + // set no quicklook radio button in GUI + quicklookNone.setValue(true, true); + } else { + Document dom = XMLParser.parse(quicklookParametersValue); + + // bandName + String bandNameValue = getTagValue(dom, "bandName"); + if (bandNameValue != null) { + bandName.setValue(bandNameValue); + + // As bandName has a value, assume this is a single band + // Therefore, set single band radio button in GUI + quicklookSingleBand.setValue(true, true); + } + + // color palette + String cpdURLValue = getTagValue(dom, "cpdURL"); + if (cpdURLValue == null || this.availableColorPalettes == null) { + colorPalette.setSelectedIndex(0); + } else { + for (int i = 0; i < this.availableColorPalettes.length; i++) { + if (this.availableColorPalettes[i].getCpdURL().equals(cpdURLValue)) { + colorPalette.setSelectedIndex(i + 1); + break; + } + } + } + + // RGBAExpressions + String RGBAExpressionsValue = getTagValue(dom, "RGBAExpressions"); + if (RGBAExpressionsValue != null) { + String[] tokens = RGBAExpressionsValue.split(","); + int numTokens = tokens.length; + rgbaExpressionsRedBand.setValue(numTokens > 0 ? tokens[0] : null); + rgbaExpressionsGreenBand.setValue(numTokens > 1 ? tokens[1] : null); + rgbaExpressionsBlueBand.setValue(numTokens > 2 ? tokens[2] : null); + rgbaExpressionsAlphaBand.setValue(numTokens > 3 ? tokens[3] : null); + + // As RGBAExpressions has a value, assume this is a multi band, + // Therefore, set multi band radio button in GUI + quicklookMultiBand.setValue(true, true); + } else { + rgbaExpressionsRedBand.setValue(null); + rgbaExpressionsGreenBand.setValue(null); + rgbaExpressionsBlueBand.setValue(null); + rgbaExpressionsAlphaBand.setValue(null); + } + + // rgbaMinSamples + String rgbaMinSamplesValue = getTagValue(dom, "rgbaMinSamples"); + rgbaMinSamples.setValue(rgbaMinSamplesValue); + + // rgbaMaxSamples + String rgbaMaxSamplesValue = getTagValue(dom, "rgbaMaxSamples"); + rgbaMaxSamples.setValue(rgbaMaxSamplesValue); + + // imageType + String imageTypeValue = getTagValue(dom, "imageType"); + if (imageTypeValue == null) + imageType.setSelectedIndex(0); + else if (imageTypeValue.equalsIgnoreCase("jpeg")) + imageType.setSelectedIndex(0); + else if (imageTypeValue.equalsIgnoreCase("png")) + imageType.setSelectedIndex(1); + else if (imageTypeValue.equalsIgnoreCase("tiff")) + imageType.setSelectedIndex(2); + else if (imageTypeValue.equalsIgnoreCase("geotiff")) + imageType.setSelectedIndex(3); + + // overlayURL + String overlayURLValue = getTagValue(dom, "overlayURL"); + overlayURL.setValue(overlayURLValue); + + // maskOverlays + String maskOverlaysValue = getTagValue(dom, "maskOverlays"); + maskOverlays.setValue(maskOverlaysValue); + + // subSamplingX + String subSamplingXValue = getTagValue(dom, "subSamplingX"); + try { + Integer subSamplingXIntValue = Integer.valueOf(subSamplingXValue); + subSamplingX.setValue(subSamplingXIntValue); + } catch (NumberFormatException e) { + subSamplingX.setValue(null); + } + + // subSamplingY + String subSamplingYValue = getTagValue(dom, "subSamplingY"); + try { + Integer subSamplingYIntValue = Integer.valueOf(subSamplingYValue); + subSamplingY.setValue(subSamplingYIntValue); + } catch (NumberFormatException e) { + subSamplingY.setValue(null); + } + + // backgroundColor + String backgroundColorValue = getTagValue(dom, "backgroundColor"); + backgroundColor.setValue(backgroundColorValue); + + // legendEnabled + String legendEnabledValue = getTagValue(dom, "legendEnabled"); + if (legendEnabledValue != null && legendEnabledValue.equalsIgnoreCase("true")) + legendEnabled.setValue(true); + else + legendEnabled.setValue(false); + + // geoServerRestUrl + String geoServerRestUrlValue = getTagValue(dom, "geoServerRestUrl"); + geoServerRestUrl.setValue(geoServerRestUrlValue); + + // geoServerUsername + String geoServerUsernameValue = getTagValue(dom, "geoServerUsername"); + geoServerUsername.setValue(geoServerUsernameValue); + + // geoServerPassword + String geoServerPasswordValue = getTagValue(dom, "geoServerPassword"); + geoServerPassword.setValue(geoServerPasswordValue); + + // geoServerWorkspace + String geoServerWorkspaceValue = getTagValue(dom, "geoServerWorkspace"); + geoServerWorkspace.setValue(geoServerWorkspaceValue); + + // geoServerStore + String geoServerStoreValue = getTagValue(dom, "geoServerStore"); + geoServerStore.setValue(geoServerStoreValue); + + // geoServerLayer + String geoServerLayerValue = getTagValue(dom, "geoServerLayer"); + geoServerLayer.setValue(geoServerLayerValue); + + // geoServerStyle + String geoServerStyleValue = getTagValue(dom, "geoServerStyle"); + geoServerStyle.setValue(geoServerStyleValue); + } + } + + private String getTagValue(Document dom, String tagName) { + NodeList nodeList = dom.getElementsByTagName(tagName); + if (nodeList != null && nodeList.getLength() > 0) { + Node node = nodeList.item(0); + if (node != null && node.hasChildNodes()) { + Node firstChild = node.getFirstChild(); + if (firstChild != null) { + return (firstChild.getNodeValue()); + } + } + } + return null; + } +} + diff --git a/calvalus-portal/src/main/java/com/bc/calvalus/portal/server/BackendServiceImpl.java b/calvalus-portal/src/main/java/com/bc/calvalus/portal/server/BackendServiceImpl.java index 9e5cf3d09..dd17487de 100644 --- a/calvalus-portal/src/main/java/com/bc/calvalus/portal/server/BackendServiceImpl.java +++ b/calvalus-portal/src/main/java/com/bc/calvalus/portal/server/BackendServiceImpl.java @@ -29,6 +29,7 @@ import com.bc.calvalus.portal.shared.BackendServiceException; import com.bc.calvalus.portal.shared.DtoAggregatorDescriptor; import com.bc.calvalus.portal.shared.DtoCalvalusConfig; +import com.bc.calvalus.portal.shared.DtoColorPalette; import com.bc.calvalus.portal.shared.DtoMaskDescriptor; import com.bc.calvalus.portal.shared.DtoParameterDescriptor; import com.bc.calvalus.portal.shared.DtoProcessState; @@ -247,6 +248,29 @@ public void storeRegions(DtoRegion[] regions) throws BackendServiceException { } } + @Override + public DtoColorPalette[] loadColorPalettes(String filter) throws BackendServiceException { + ColorPalettePersistence colorPalettePersistence = new ColorPalettePersistence(getUserName(), ProductionServiceConfig.getUserAppDataDir()); + try { + DtoColorPalette[] dtoColorPalettes = colorPalettePersistence.loadColorPalettes(); + LOG.fine("loadColorPalettes returns " + dtoColorPalettes.length); + return dtoColorPalettes; + } catch (IOException e) { + log(e.getMessage(), e); + throw new BackendServiceException("Failed to load color palettes: " + e.getMessage(), e); + } + } + + @Override + public void storeColorPalettes(DtoColorPalette[] colorPalettes) throws BackendServiceException { + ColorPalettePersistence colorPalettePersistence = new ColorPalettePersistence(getUserName(), ProductionServiceConfig.getUserAppDataDir()); + try { + colorPalettePersistence.storeColorPalettes(colorPalettes); + } catch (IOException e) { + throw new BackendServiceException("Failed to store color palettes: " + e.getMessage(), e); + } + } + @Override public DtoProductSet[] getProductSets(String filter) throws BackendServiceException { if (filter.contains("dummy")) { diff --git a/calvalus-portal/src/main/java/com/bc/calvalus/portal/server/ColorPalettePersistence.java b/calvalus-portal/src/main/java/com/bc/calvalus/portal/server/ColorPalettePersistence.java new file mode 100644 index 000000000..20ec4c795 --- /dev/null +++ b/calvalus-portal/src/main/java/com/bc/calvalus/portal/server/ColorPalettePersistence.java @@ -0,0 +1,111 @@ +package com.bc.calvalus.portal.server; + +import com.bc.calvalus.portal.shared.DtoColorPalette; + +import java.io.*; +import java.util.*; + +/** + * A location that stores color palettes. + * + * @author Declan + */ +public class ColorPalettePersistence { + + private final String userName; + private final File userAppDataDir; + + public ColorPalettePersistence(String userName, File userAppDataDir) { + this.userName = userName; + this.userAppDataDir = userAppDataDir; + } + + public DtoColorPalette[] loadColorPalettes() throws IOException { + Properties colorPaletteProperties = loadDefaultColorPalettes(); + Properties userColorPaletteProperties = loadUserColorPalettes(); + colorPaletteProperties.putAll(userColorPaletteProperties); + + ArrayList colorPalettes = new ArrayList(); + Set colorPaletteNames = colorPaletteProperties.stringPropertyNames(); + for (String colorPaletteFullName : colorPaletteNames) { + String[] split = colorPaletteFullName.split("\\."); + String colorPaletteName = split[split.length - 1]; + String[] colorPalettePath = Arrays.copyOf(split, split.length - 1); + String cpdURL = colorPaletteProperties.getProperty(colorPaletteFullName); + DtoColorPalette colorPalette = new DtoColorPalette(colorPaletteName, colorPalettePath, cpdURL); + colorPalettes.add(colorPalette); + } + + Collections.sort(colorPalettes, new Comparator() { + @Override + public int compare(DtoColorPalette o1, DtoColorPalette o2) { + return o1.getQualifiedName().compareToIgnoreCase(o2.getQualifiedName()); + } + }); + return colorPalettes.toArray(new DtoColorPalette[colorPalettes.size()]); + } + + public void storeColorPalettes(DtoColorPalette[] colorPalettes) throws IOException { + Properties userColorPalettes = getUserColorPalettes(colorPalettes); + File file = getColorPaletteFile(getUserName()); + file.getParentFile().mkdirs(); + FileWriter fileWriter = new FileWriter(file); + try { + userColorPalettes.store(fileWriter, "Calvalus color palettes for user " + getUserName()); + } finally { + fileWriter.close(); + } + } + + private File getColorPaletteFile(String user) { + return new File(userAppDataDir, user + "-color-palettes.properties"); + } + + private String getUserName() { + return userName; + } + + private Properties getUserColorPalettes(DtoColorPalette[] colorPalettes) { + Properties userColorPalettes = new Properties(); + for (DtoColorPalette colorPalette : colorPalettes) { + if (colorPalette.isUserColorPalette()) { + String fullName = colorPalette.getQualifiedName(); + System.out.println("storing color palette " + fullName + " = " + colorPalette.getCpdURL()); + userColorPalettes.put(fullName, colorPalette.getCpdURL()); + } + } + return userColorPalettes; + } + + private Properties loadDefaultColorPalettes() throws IOException { + InputStream stream = getClass().getResourceAsStream("color-palettes.properties"); + Properties systemColorPalettes = loadColorPalettes(new BufferedReader(new InputStreamReader(stream))); + + File additionalSystemColorPaletteFile = getColorPaletteFile("SYSTEM"); + if (additionalSystemColorPaletteFile.exists()) { + Properties additionalSystemColorPalettes = loadColorPalettes(new FileReader(additionalSystemColorPaletteFile)); + systemColorPalettes.putAll(additionalSystemColorPalettes); + } + return systemColorPalettes; + } + + private Properties loadUserColorPalettes() throws IOException { + File userColorPaletteFile = getColorPaletteFile(getUserName()); + if (userColorPaletteFile.exists()) { + return loadColorPalettes(new FileReader(userColorPaletteFile)); + } else { + return new Properties(); + } + } + + private Properties loadColorPalettes(Reader stream) throws IOException { + Properties colorPalettes = new Properties(); + try { + colorPalettes.load(stream); + } finally { + stream.close(); + } + return colorPalettes; + } + +} diff --git a/calvalus-portal/src/main/java/com/bc/calvalus/portal/shared/BackendService.java b/calvalus-portal/src/main/java/com/bc/calvalus/portal/shared/BackendService.java index d2024b5d0..f1525f35e 100644 --- a/calvalus-portal/src/main/java/com/bc/calvalus/portal/shared/BackendService.java +++ b/calvalus-portal/src/main/java/com/bc/calvalus/portal/shared/BackendService.java @@ -32,6 +32,26 @@ public interface BackendService extends RemoteService { */ void storeRegions(DtoRegion[] regions) throws BackendServiceException; + /** + * Gets all known color palettes. + * + * @param filter A filter expression (not yet used). + * + * @return The array of color palettes. + * + * @throws BackendServiceException If a server error occurred. + */ + DtoColorPalette[] loadColorPalettes(String filter) throws BackendServiceException; + + /** + * Persists the provided color palettes. + * + * @param colorPalettes The color palettes to persist. + * + * @throws BackendServiceException If a server error occurred. + */ + void storeColorPalettes(DtoColorPalette[] colorPalettes) throws BackendServiceException; + /** * Gets all known product sets. * diff --git a/calvalus-portal/src/main/java/com/bc/calvalus/portal/shared/BackendServiceAsync.java b/calvalus-portal/src/main/java/com/bc/calvalus/portal/shared/BackendServiceAsync.java index 165fb7198..1bad84fcd 100644 --- a/calvalus-portal/src/main/java/com/bc/calvalus/portal/shared/BackendServiceAsync.java +++ b/calvalus-portal/src/main/java/com/bc/calvalus/portal/shared/BackendServiceAsync.java @@ -13,6 +13,10 @@ public interface BackendServiceAsync { void storeRegions(DtoRegion[] regions, AsyncCallback callback); + void loadColorPalettes(String filter, AsyncCallback callback); + + void storeColorPalettes(DtoColorPalette[] colorPalettes, AsyncCallback callback); + void listUserFiles(String dir, AsyncCallback callback); void removeUserFile(String path, AsyncCallback callback); diff --git a/calvalus-portal/src/main/java/com/bc/calvalus/portal/shared/DtoColorPalette.java b/calvalus-portal/src/main/java/com/bc/calvalus/portal/shared/DtoColorPalette.java new file mode 100644 index 000000000..864abfcb4 --- /dev/null +++ b/calvalus-portal/src/main/java/com/bc/calvalus/portal/shared/DtoColorPalette.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2018 Brockmann Consult GmbH (info@brockmann-consult.de) + * + * 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 3 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/ + */ + +package com.bc.calvalus.portal.shared; + +import com.google.gwt.user.client.rpc.IsSerializable; + +/** + * @author Declan + */ +public class DtoColorPalette implements IsSerializable { + + private String name; + private String[] path; + private String cpdURL; + + /** + * No-arg constructor as required by {@link IsSerializable}. Don't use directly. + */ + public DtoColorPalette() { + } + + public DtoColorPalette(String name, String[] path, String cpdURL) { + if (name == null) { + throw new NullPointerException("name"); + } + if (path == null) { + throw new NullPointerException("path"); + } + if (path == null) { + throw new NullPointerException("cpdURL"); + } + this.name = name; + this.path = path; + this.cpdURL = cpdURL; + } + + public String getName() { + return name; + } + + public String[] getPath() { + return path; + } + + public String getCpdURL() { + return cpdURL; + } + + public boolean isUserColorPalette() { + return path != null && path.length > 0 && "user".equals(path[0]); + } + + public String getQualifiedName() { + StringBuilder sb = new StringBuilder(); + for (String pathElement : path) { + sb.append(pathElement); + sb.append("."); + } + sb.append(name); + return sb.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + DtoColorPalette that = (DtoColorPalette) o; + + if (!name.equals(that.name)) { + return false; + } + if (!path.equals(that.path)) { + return false; + } + if (!path.equals(that.cpdURL)) { + return false; + } + return true; + } +} diff --git a/calvalus-portal/src/main/resources-default/WEB-INF/classes/com/bc/calvalus/portal/client/style.css b/calvalus-portal/src/main/resources-default/WEB-INF/classes/com/bc/calvalus/portal/client/style.css index c65a29fe3..e34199ea1 100644 --- a/calvalus-portal/src/main/resources-default/WEB-INF/classes/com/bc/calvalus/portal/client/style.css +++ b/calvalus-portal/src/main/resources-default/WEB-INF/classes/com/bc/calvalus/portal/client/style.css @@ -118,6 +118,40 @@ font-size: 14px; } +/************************** +* Quicklook Panel styling * +***************************/ +.quicklookPanel { + margin: 0px 15px 50px 15px; + width: 62em; +} + +.quicklookRadioPanel { + padding: 5px 0px 5px 0px; +} + +.quicklookRadioButton { + font-family: Calibri, Verdana, Arial, sans-serif; + font-size: 14px; + color: black; + padding-right: 10px; +} + +.quicklookParametersPanel { + display: flex; +} + +.quicklookInputLabelCell { + font-family: Calibri, Verdana, Arial, sans-serif; + font-size: 14px; + width: 185px; +} + +.quicklookInputCell { + font-family: Calibri, Verdana, Arial, sans-serif; + font-size: 14px; +} + /********************** * Input files styling * ***********************/ @@ -226,4 +260,4 @@ font-size: 14px; font-weight: 700; color: #777799; -} \ No newline at end of file +} diff --git a/calvalus-portal/src/main/resources/com/bc/calvalus/portal/CalvalusPortal.gwt.xml b/calvalus-portal/src/main/resources/com/bc/calvalus/portal/CalvalusPortal.gwt.xml index e7a6bf344..3ad07324a 100644 --- a/calvalus-portal/src/main/resources/com/bc/calvalus/portal/CalvalusPortal.gwt.xml +++ b/calvalus-portal/src/main/resources/com/bc/calvalus/portal/CalvalusPortal.gwt.xml @@ -17,6 +17,8 @@ + + diff --git a/calvalus-portal/src/main/resources/com/bc/calvalus/portal/client/QuicklookParametersForm.ui.xml b/calvalus-portal/src/main/resources/com/bc/calvalus/portal/client/QuicklookParametersForm.ui.xml new file mode 100755 index 000000000..3ab85b874 --- /dev/null +++ b/calvalus-portal/src/main/resources/com/bc/calvalus/portal/client/QuicklookParametersForm.ui.xml @@ -0,0 +1,462 @@ + + + + + + + + + Quicklook + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
   
+ Band name: + + +
+ + + +
    + + The name of a band which will be used for the image. + +
   
+ Colour table: + + +
    + + The colour table which will be applied to the chosen band. + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
   
+ Red band expression: + + +
+ Green band expression: + + +
+ Blue band expression: + + +
+ Alpha band expression: + + +
    + + Add a list of 3 or 4 band names from which an RGB or RGBA colourised image will be + generated (A=alpha channel). + +
   
+ Minimum samples: + + +
+ Maximum samples: + + +
    + + Add a list of 3 or 4 values that set minimal and maximal values for the displayed samples. + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
   
+ Image type: + + +
    + + The type of the generated image. + +
   
+ Background Colour: + + +
    + + The background colour of the generated image. + +
   
+ Overlay URL: + + +
    + + A URL to a file containing a image that will be rendered above the image from the product. + +
   
+ Mask overlays: + + +
    + + Defines which product mask should be drawn on top of + the actual band or RGB image. The product must contain + the specified masks. + +
   
+ Sub sampling (X): + + +
+ Sub sampling (Y): + + +
    + + Sub sampling can be used to reduce the size of the resulting image. + The default size of the image is identical to the size of the product. + +
   
+ Legend + + +
    + + When set, an image legend will be drawn into the bottom-right corner of the image. + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
   
+ GeoServer REST URL: + + +
    + + The URL to GeoServer's REST API (e.g. http://myhost/geoserver/rest/ + +
   
+ GeoServer username: + + +
    + + The username for GeoServer authentication + +
   
+ GeoServer password: + + +
    + + The password for GeoServer authentication + +
   
+ GeoServer workspace: + + +
    + + The GeoServer workspace's name + +
   
+ GeoServer store: + + +
    + + The GeoServer store's name + +
   
+ GeoServer layer: + + +
    + + The GeoServer layer's name + +
   
+ GeoServer style: + + +
    + + The GeoServer style name + +
+ +
+ + +
+
+ +
+ +
diff --git a/calvalus-portal/src/main/resources/com/bc/calvalus/portal/server/color-palettes.properties b/calvalus-portal/src/main/resources/com/bc/calvalus/portal/server/color-palettes.properties new file mode 100644 index 000000000..69dde0080 --- /dev/null +++ b/calvalus-portal/src/main/resources/com/bc/calvalus/portal/server/color-palettes.properties @@ -0,0 +1,26 @@ +5_colors = hdfs://master00:9000/calvalus/auxiliary/cpd/5_colors.cpd +7_colors = hdfs://master00:9000/calvalus/auxiliary/cpd/7_colors.cpd +cc_chl = hdfs://master00:9000/calvalus/auxiliary/cpd/cc_chl.cpd +cc_general = hdfs://master00:9000/calvalus/auxiliary/cpd/cc_general.cpd +cc_iop_quality = hdfs://master00:9000/calvalus/auxiliary/cpd/cc_iop_quality.cpd +cc_tsm = hdfs://master00:9000/calvalus/auxiliary/cpd/cc_tsm.cpd +cc_yellowsubstance = hdfs://master00:9000/calvalus/auxiliary/cpd/cc_yellowsubstance.cpd +cc_z90 = hdfs://master00:9000/calvalus/auxiliary/cpd/cc_z90.cpd +CHL_SeaWiFS = hdfs://master00:9000/calvalus/auxiliary/cpd/CHL_SeaWiFS.cpd +cubehelix_cycle = hdfs://master00:9000/calvalus/auxiliary/cpd/cubehelix_cycle.cpd +gradient_8_colors = hdfs://master00:9000/calvalus/auxiliary/cpd/gradient_8_colors.cpd +gradient_blue = hdfs://master00:9000/calvalus/auxiliary/cpd/gradient_blue.cpd +gradient_green = hdfs://master00:9000/calvalus/auxiliary/cpd/gradient_green.cpd +gradient_red = hdfs://master00:9000/calvalus/auxiliary/cpd/gradient_red.cpd +gradient_red_white_blue = hdfs://master00:9000/calvalus/auxiliary/cpd/gradient_red_white_blue.cpd +great_circle = hdfs://master00:9000/calvalus/auxiliary/cpd/great_circle.cpd +JET = hdfs://master00:9000/calvalus/auxiliary/cpd/JET.cpd +meris_algal = hdfs://master00:9000/calvalus/auxiliary/cpd/meris_algal.cpd +meris_case2 = hdfs://master00:9000/calvalus/auxiliary/cpd/meris_case2.cpd +meris_cloud = hdfs://master00:9000/calvalus/auxiliary/cpd/meris_cloud.cpd +meris_pressure = hdfs://master00:9000/calvalus/auxiliary/cpd/meris_pressure.cpd +meris_veg_index = hdfs://master00:9000/calvalus/auxiliary/cpd/meris_veg_index.cpd +meris_wind_direction = hdfs://master00:9000/calvalus/auxiliary/cpd/meris_wind_direction.cpd +spectrum = hdfs://master00:9000/calvalus/auxiliary/cpd/spectrum.cpd +spectrum_large = hdfs://master00:9000/calvalus/auxiliary/cpd/spectrum_large.cpd +terrain = hdfs://master00:9000/calvalus/auxiliary/cpd/terrain.cpd diff --git a/calvalus-processing/src/main/java/com/bc/calvalus/processing/analysis/GeoServer.java b/calvalus-processing/src/main/java/com/bc/calvalus/processing/analysis/GeoServer.java new file mode 100644 index 000000000..e76401ba3 --- /dev/null +++ b/calvalus-processing/src/main/java/com/bc/calvalus/processing/analysis/GeoServer.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2019 Brockmann Consult GmbH (info@brockmann-consult.de) + * + * 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 3 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/ + */ + +package com.bc.calvalus.processing.analysis; + +import com.bc.calvalus.commons.CalvalusLogger; +import org.apache.commons.io.IOUtils; +import org.apache.hadoop.mapreduce.TaskAttemptContext; +import org.esa.snap.core.datamodel.Product; + +import java.io.*; +import java.net.Authenticator; +import java.net.HttpURLConnection; +import java.net.PasswordAuthentication; +import java.net.URL; +import java.util.logging.Logger; + +/** + * GeoServer REST API handler + * + * @author Declan + */ +public class GeoServer { + + private static final Logger LOGGER = CalvalusLogger.getLogger(); + + private final TaskAttemptContext context; + private final Product sourceProduct; + private final Quicklooks.QLConfig qlConfig; + + public GeoServer(TaskAttemptContext context, Product product, Quicklooks.QLConfig qlConfig) { + this.context = context; + this.sourceProduct = product; + this.qlConfig = qlConfig; + } + + public void uploadImage(InputStream inputStream, String imageName) throws IOException { + + String msg = String.format("Uploading product image '%s' to GeoServer.", imageName); + LOGGER.info(msg); + + String geoserverRestURL = this.qlConfig.getGeoServerRestUrl(); + String username = this.qlConfig.getGeoServerUsername(); + String password = this.qlConfig.getGeoServerPassword(); + String workspace = this.qlConfig.getGeoServerWorkspace(); + String store = this.qlConfig.getGeoServerStore(); + String layer = this.qlConfig.getGeoServerLayer(); + String style = this.qlConfig.getGeoServerStyle(); + + if (geoserverRestURL == null || geoserverRestURL.isEmpty()) { + throw new IllegalArgumentException("geoserverRestURL is empty"); + } + geoserverRestURL = geoserverRestURL.trim(); + while (geoserverRestURL.endsWith("/")) { + geoserverRestURL = geoserverRestURL.substring(0, geoserverRestURL.length() - 1); + } + + if (workspace == null || workspace.isEmpty()) { + throw new IllegalArgumentException("workspace is empty"); + } + + if (store == null || store.isEmpty()) { + store = imageName; + } + else { + store.trim(); + } + + if (layer == null || layer.isEmpty()) { + layer = imageName; + } + else { + layer.trim(); + } + + if (username != null && !username.isEmpty() && password != null) { + Authenticator.setDefault(new Authenticator() { + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password.toCharArray()); + } + }); + } + + // other functionality for future (not required at present) + //getCoverageStore(geoserverURL, workspace, layerID); + //deleteCoverageStore(geoserverURL, workspace, layerID); + + putCoverageStoreSingleGeoTiff(inputStream, geoserverRestURL, workspace, store, layer); + + if (style != null && !style.isEmpty()) { + putLayerStyle(geoserverRestURL, workspace, layer, style); + } + } + + /** + * Get a coverage store named {storeName} in the {workspace} workspace + * + * @param geoserverRestURL the root URL to GeoServer + * @param workspace the name of the workspace containing the coverage stores + * @param store the name of the store to be retrieved + */ + public void getCoverageStore(String geoserverRestURL, String workspace, String store) throws IOException { + String getCoverageStoreURL = String.format("%s/workspaces/%s/coveragestores/%s", geoserverRestURL, workspace, store); + LOGGER.info("Getting GeoServer coverage store: " + getCoverageStoreURL); + + URL url = new URL(getCoverageStoreURL); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoOutput(true); + conn.setInstanceFollowRedirects(false); + conn.setUseCaches(false); + conn.setRequestProperty("Content-Type", "application/xml"); + conn.setRequestProperty("charset", "utf-8"); + conn.setRequestMethod("GET"); + + int responseCode = conn.getResponseCode(); + String responseMessage = conn.getResponseMessage(); + LOGGER.info("GeoServer response: " + responseCode + ": " + responseMessage); + conn.disconnect(); + } + + /** + * Delete a coverage store named {storeName} in the {workspace} workspace + * + * @param geoserverRestURL the root URL to GeoServer + * @param workspace the name of the workspace containing the coverage stores + * @param store the name of the store to be deleted + */ + public void deleteCoverageStore(String geoserverRestURL, String workspace, String store) throws IOException { + String deleteCoverageStoreURL = String.format("%/workspaces/%s/coveragestores/%s?recurse=true&purge=all", geoserverRestURL, workspace, store); + LOGGER.info("Deleting GeoServer coverage store: " + deleteCoverageStoreURL); + + URL url = new URL(deleteCoverageStoreURL); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoOutput(true); + conn.setInstanceFollowRedirects(false); + conn.setUseCaches(false); + //conn.setRequestProperty("Content-Type", "application/xml"); + //conn.setRequestProperty("charset", "utf-8"); + conn.setRequestMethod("DELETE"); + + int responseCode = conn.getResponseCode(); + String responseMessage = conn.getResponseMessage(); + LOGGER.info("GeoServer response: " + responseCode + ": " + responseMessage); + conn.disconnect(); + } + + /** + * Creates or overwrites a single coverage store by uploading its GeoTIFF raster data file + * + * @param inputStream an InputStream to the GeoTIFF for updating + * @param geoserverRestURL the root URL to GeoServer + * @param workspace the name of the workspace containing the coverage stores + * @param store the name of the store to be created or overwritten + * @param layer the name of the new layer + */ + public void putCoverageStoreSingleGeoTiff(InputStream inputStream, String geoserverRestURL, String workspace, String store, String layer) throws IOException { + String putCoverageStoreURL = String.format("%s/workspaces/%s/coveragestores/%s/file.geotiff?coverageName=%s", geoserverRestURL, workspace, store, layer); + LOGGER.info("Uploading GeoTIFF to the GeoServer coverage store: " + putCoverageStoreURL); + + byte[] geoTiffPayload = IOUtils.toByteArray(inputStream); + LOGGER.info("GeoTIFF size (bytes): " + geoTiffPayload.length); + + URL url = new URL(putCoverageStoreURL); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setInstanceFollowRedirects(false); + conn.setUseCaches(false); + conn.setRequestProperty("Content-Type", "text/plain"); + //conn.setRequestProperty("charset", "utf-8"); + conn.setRequestMethod("PUT"); + + DataOutputStream out = new DataOutputStream(conn.getOutputStream()); + out.write(geoTiffPayload); + out.flush(); + out.close(); + + int responseCode = conn.getResponseCode(); + String responseMessage = conn.getResponseMessage(); + LOGGER.info("GeoServer response: " + responseCode + ": " + responseMessage); + conn.disconnect(); + } + + /** + * Modify a layer's style + * + * @param geoserverRestURL the root URL to GeoServer + * @param workspace the name of the workspace containing the coverage stores + * @param layer the name of the layer to modify + * @param style the default style to use for this layer + */ + public void putLayerStyle(String geoserverRestURL, String workspace, String layer, String style) throws IOException { + String payload = "" + style + ""; + String uploadStyleURL = String.format("%s/workspaces/%s/layers/%s", geoserverRestURL, workspace, layer); + LOGGER.info("Updating layer style to '" + style + "': " + uploadStyleURL); + + URL url = new URL(uploadStyleURL); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setInstanceFollowRedirects(false); + conn.setUseCaches(false); + conn.setRequestProperty("Content-Type", "application/xml"); + //conn.setRequestProperty("charset", "utf-8"); + conn.setRequestMethod("PUT"); + + DataOutputStream out = new DataOutputStream(conn.getOutputStream()); + out.writeBytes(payload); + out.flush(); + out.close(); + + int responseCode = conn.getResponseCode(); + String responseMessage = conn.getResponseMessage(); + LOGGER.info("GeoServer response: " + responseCode + ": " + responseMessage); + conn.disconnect(); + } +} diff --git a/calvalus-processing/src/main/java/com/bc/calvalus/processing/analysis/QLMapper.java b/calvalus-processing/src/main/java/com/bc/calvalus/processing/analysis/QLMapper.java index 887db1d39..fd9b1c529 100644 --- a/calvalus-processing/src/main/java/com/bc/calvalus/processing/analysis/QLMapper.java +++ b/calvalus-processing/src/main/java/com/bc/calvalus/processing/analysis/QLMapper.java @@ -24,17 +24,34 @@ import com.bc.calvalus.processing.l2.L2FormattingMapper; import com.bc.ceres.core.ProgressMonitor; import com.bc.ceres.core.SubProgressMonitor; +import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.NullWritable; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; +import org.esa.snap.core.datamodel.GeoCoding; +import org.esa.snap.core.datamodel.GeoPos; +import org.esa.snap.core.datamodel.PixelPos; import org.esa.snap.core.datamodel.Product; import org.esa.snap.core.util.io.FileUtils; +import org.geotools.coverage.grid.GridCoverage2D; +import org.geotools.coverage.grid.GridCoverageFactory; +import org.geotools.coverage.grid.io.AbstractGridFormat; +//import org.geotools.coverage.grid.io.imageio.GeoToolsWriteParams; +import org.geotools.gce.geotiff.GeoTiffFormat; +import org.geotools.gce.geotiff.GeoTiffWriteParams; +import org.geotools.geometry.jts.ReferencedEnvelope; +import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.opengis.coverage.grid.GridCoverageWriter; +import org.opengis.parameter.GeneralParameterValue; +import org.opengis.parameter.ParameterValueGroup; import javax.imageio.ImageIO; import java.awt.image.RenderedImage; +import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.util.logging.Logger; @@ -61,18 +78,25 @@ public void run(Mapper.Context context) throws IOException, InterruptedException final String productName = FileUtils.getFilenameWithoutExtension(inputFileName); final Quicklooks.QLConfig[] configs = Quicklooks.get(context.getConfiguration()); for (Quicklooks.QLConfig config : configs) { - final String imageFileName; + final String imageBaseName; if (context.getConfiguration().get(JobConfigNames.CALVALUS_OUTPUT_REGEX) != null && context.getConfiguration().get(JobConfigNames.CALVALUS_OUTPUT_REPLACEMENT) != null) { if (configs.length == 1) { - imageFileName = L2FormattingMapper.getProductName(context.getConfiguration(), inputFileName); + imageBaseName = L2FormattingMapper.getProductName(context.getConfiguration(), inputFileName); } else { - imageFileName = L2FormattingMapper.getProductName(context.getConfiguration(), inputFileName) + "_" + config.getBandName(); + imageBaseName = L2FormattingMapper.getProductName(context.getConfiguration(), inputFileName) + "_" + config.getBandName(); } } else { - imageFileName = productName + "_" + config.getBandName(); + imageBaseName = productName + "_" + config.getBandName(); + } + createQuicklook(product, imageBaseName, context, config); + if( config.getGeoServerRestUrl() != null ) { + // upload geoTiff to GeoServer + GeoServer geoserver = new GeoServer(context, product, config); + String imageFilename = QLMapper.getImageFileName(imageBaseName, config); + InputStream inputStream = QLMapper.createInputStream(context, imageFilename); + geoserver.uploadImage(inputStream, imageBaseName); } - createQuicklook(product, imageFileName, context, config); } } } finally { @@ -81,17 +105,60 @@ public void run(Mapper.Context context) throws IOException, InterruptedException } } - public static void createQuicklook(Product product, String imageFileName, Mapper.Context context, + public static void createQuicklook(Product product, String imageBaseName, Mapper.Context context, Quicklooks.QLConfig config) throws IOException, InterruptedException { // try { + String imageFileName = getImageFileName(imageBaseName, config); RenderedImage quicklookImage = new QuicklookGenerator(context, product, config).createImage(); if (quicklookImage != null) { - OutputStream outputStream = createOutputStream(context, imageFileName + "." + config.getImageType()); - OutputStream pmOutputStream = new BytesCountingOutputStream(outputStream, context); - try { - ImageIO.write(quicklookImage, config.getImageType(), pmOutputStream); - } finally { - outputStream.close(); + if( isGeoTiff(config)) { + OutputStream outputStream = createOutputStream(context, imageFileName); + LOGGER.info("outputStream: " + outputStream.toString()); + OutputStream pmOutputStream = new BytesCountingOutputStream(outputStream, context); + + final int width = product.getSceneRasterWidth(); + final int height = product.getSceneRasterHeight(); + final GeoCoding geoCoding = product.getSceneGeoCoding(); + final PixelPos posA = new org.esa.snap.core.datamodel.PixelPos(0, 0); + final GeoPos geoPosA = geoCoding.getGeoPos(posA, null); + final PixelPos posB = new org.esa.snap.core.datamodel.PixelPos(width, height); + final GeoPos geoPosB = geoCoding.getGeoPos(posB, null); + + final GeoTiffFormat format = new GeoTiffFormat(); + final GeoTiffWriteParams wp = new GeoTiffWriteParams(); + //wp.setCompressionMode(GeoTiffWriteParams.MODE_EXPLICIT); + //wp.setCompressionType("LZW"); + //wp.setCompressionQuality(1.0F); + //wp.setTilingMode(GeoToolsWriteParams.MODE_EXPLICIT); + //wp.setTiling(256, 256); + final ParameterValueGroup params = format.getWriteParameters(); + params.parameter(AbstractGridFormat.GEOTOOLS_WRITE_PARAMS.getName().toString()).setValue(wp); + + try { + ReferencedEnvelope envelope = + new ReferencedEnvelope( + geoPosA.getLon(), geoPosB.getLon(), + geoPosA.getLat(), geoPosB.getLat(), + DefaultGeographicCRS.WGS84 + ); + GridCoverageFactory factory = new GridCoverageFactory(); + GridCoverage2D gridCoverage2D = factory.create(imageFileName, quicklookImage, envelope); + GridCoverageWriter writer = format.getWriter(new BufferedOutputStream(pmOutputStream)); + writer.write(gridCoverage2D, params.values().toArray(new GeneralParameterValue[1])); + writer.dispose(); + } finally { + outputStream.close(); + } + } + else { + OutputStream outputStream = createOutputStream(context, imageFileName); + LOGGER.info("outputStream: " + outputStream.toString()); + OutputStream pmOutputStream = new BytesCountingOutputStream(outputStream, context); + try { + ImageIO.write(quicklookImage, config.getImageType(), pmOutputStream); + } finally { + outputStream.close(); + } } } // } catch (Exception e) { @@ -100,12 +167,37 @@ public static void createQuicklook(Product product, String imageFileName, Mapper // } } + + public static String getImageFileName(String imageBaseName, Quicklooks.QLConfig qlConfig) { + if( isGeoTiff(qlConfig)) { + return imageBaseName + ".tiff"; + } + else { + return imageBaseName + "." + qlConfig.getImageType(); + } + } + + public static Path getWorkOutputFilePath(Mapper.Context context, String fileName) throws IOException, InterruptedException { + return new Path(FileOutputFormat.getWorkOutputPath(context), fileName); + } + + private static boolean isGeoTiff(Quicklooks.QLConfig qlConfig) { + return "geotiff".equalsIgnoreCase(qlConfig.getImageType()); + } + private static OutputStream createOutputStream(Mapper.Context context, String fileName) throws IOException, InterruptedException { - Path path = new Path(FileOutputFormat.getWorkOutputPath(context), fileName); + Path path = getWorkOutputFilePath(context, fileName); + LOGGER.info("createOutputStream: path = " + path); final FSDataOutputStream fsDataOutputStream = path.getFileSystem(context.getConfiguration()).create(path); return new BufferedOutputStream(fsDataOutputStream); } + public static InputStream createInputStream(Mapper.Context context, String fileName) throws IOException, InterruptedException { + Path path = getWorkOutputFilePath(context, fileName); + LOGGER.info("createInputStream: path = " + path); + final FSDataInputStream fsDataInputStream = path.getFileSystem(context.getConfiguration()).open(path); + return new BufferedInputStream(fsDataInputStream); + } private static class BytesCountingOutputStream extends OutputStream { diff --git a/calvalus-processing/src/main/java/com/bc/calvalus/processing/analysis/Quicklooks.java b/calvalus-processing/src/main/java/com/bc/calvalus/processing/analysis/Quicklooks.java index d3345d1e9..8d8892302 100644 --- a/calvalus-processing/src/main/java/com/bc/calvalus/processing/analysis/Quicklooks.java +++ b/calvalus-processing/src/main/java/com/bc/calvalus/processing/analysis/Quicklooks.java @@ -76,6 +76,21 @@ public static class QLConfig { @Parameter private String shapefileURL; + @Parameter + private String geoServerRestUrl; + @Parameter + private String geoServerUsername; + @Parameter + private String geoServerPassword; + @Parameter + private String geoServerWorkspace; + @Parameter + private String geoServerStore; + @Parameter + private String geoServerLayer; + @Parameter + private String geoServerStyle; + public String getImageType() { return imageType; } @@ -155,5 +170,34 @@ public void setLegendEnabled(boolean legendEnabled) { public void setOverlayURL(String overlayURL) { this.overlayURL = overlayURL; } + + public String getGeoServerRestUrl() { + return geoServerRestUrl; + } + + public String getGeoServerUsername() { + return geoServerUsername; + } + + public String getGeoServerPassword() { + return geoServerPassword; + } + + public String getGeoServerWorkspace() { + return geoServerWorkspace; + } + + public String getGeoServerStore() { + return geoServerStore; + } + + public String getGeoServerLayer() { + return geoServerLayer; + } + + public String getGeoServerStyle() { + return geoServerStyle; + } + } } diff --git a/calvalus-processing/src/main/java/com/bc/calvalus/processing/l2/L2FormattingMapper.java b/calvalus-processing/src/main/java/com/bc/calvalus/processing/l2/L2FormattingMapper.java index ac3314873..79ec753df 100644 --- a/calvalus-processing/src/main/java/com/bc/calvalus/processing/l2/L2FormattingMapper.java +++ b/calvalus-processing/src/main/java/com/bc/calvalus/processing/l2/L2FormattingMapper.java @@ -21,6 +21,7 @@ import com.bc.calvalus.processing.JobConfigNames; import com.bc.calvalus.processing.ProcessorAdapter; import com.bc.calvalus.processing.ProcessorFactory; +import com.bc.calvalus.processing.analysis.GeoServer; import com.bc.calvalus.processing.analysis.QLMapper; import com.bc.calvalus.processing.analysis.Quicklooks; import com.bc.calvalus.processing.hadoop.ProgressSplitProgressMonitor; @@ -39,6 +40,7 @@ import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.text.DateFormat; import java.util.*; import java.util.logging.Level; @@ -163,22 +165,36 @@ private void writeQuicklooks(Mapper.Context context, Configuration jobConfig, St List qlConfigList = getValidQlConfigs(jobConfig); for (Quicklooks.QLConfig qlConfig : qlConfigList) { - String imageFileName; + String imageBaseName; // if (context.getConfiguration().get(JobConfigNames.CALVALUS_OUTPUT_REGEX) != null // && context.getConfiguration().get(JobConfigNames.CALVALUS_OUTPUT_REPLACEMENT) != null) { -// imageFileName = L2FormattingMapper.getProductName(context.getConfiguration(), productName); +// imageBaseName = L2FormattingMapper.getProductName(context.getConfiguration(), productName); // } else { - imageFileName = productName; + imageBaseName = productName; // } if (qlConfigList.size() > 1) { - imageFileName = imageFileName + "_" + qlConfig.getBandName(); + imageBaseName = imageBaseName + "_" + qlConfig.getBandName(); } + try { - QLMapper.createQuicklook(targetProduct, imageFileName, context, qlConfig); + QLMapper.createQuicklook(targetProduct, imageBaseName, context, qlConfig); } catch (Exception e) { String msg = String.format("Could not create quicklook image '%s'.", qlConfig.getBandName()); LOG.log(Level.WARNING, msg, e); } + + if( qlConfig.getGeoServerRestUrl() != null ) { + // upload geoTiff to GeoServer + try { + GeoServer geoserver = new GeoServer(context, targetProduct, qlConfig); + String imageFilename = QLMapper.getImageFileName(imageBaseName, qlConfig); + InputStream inputStream = QLMapper.createInputStream(context, imageFilename); + geoserver.uploadImage(inputStream, imageBaseName); + } catch (Exception e) { + String msg = String.format("Could not upload quicklook image '%s' to GeoServer.", qlConfig.getBandName()); + LOG.log(Level.WARNING, msg, e); + } + } } LOG.info("Finished creating quicklooks."); } diff --git a/calvalus-production/src/main/java/com/bc/calvalus/production/ServiceContainer.java b/calvalus-production/src/main/java/com/bc/calvalus/production/ServiceContainer.java index 10d9ae3d1..92fe8f216 100644 --- a/calvalus-production/src/main/java/com/bc/calvalus/production/ServiceContainer.java +++ b/calvalus-production/src/main/java/com/bc/calvalus/production/ServiceContainer.java @@ -31,7 +31,7 @@ public class ServiceContainer { public ServiceContainer(ProductionService productionService, FileSystemService fileSystemService, - InventoryService inventoryService, + InventoryService inventoryService, Configuration hadoopConfiguration) { this.productionService = productionService; this.fileSystemService = fileSystemService; diff --git a/calvalus-production/src/main/java/com/bc/calvalus/production/hadoop/QLProductionType.java b/calvalus-production/src/main/java/com/bc/calvalus/production/hadoop/QLProductionType.java index 1c1d84582..c04a52843 100644 --- a/calvalus-production/src/main/java/com/bc/calvalus/production/hadoop/QLProductionType.java +++ b/calvalus-production/src/main/java/com/bc/calvalus/production/hadoop/QLProductionType.java @@ -64,23 +64,17 @@ public Production createProduction(ProductionRequest productionRequest) throws P // todo - if autoStaging=true, create sequential workflow and add staging job String stagingDir = productionRequest.getStagingDirectory(productionId); - //boolean autoStaging = productionRequest.isAutoStaging(); //TODO - boolean autoStaging = false; + boolean autoStaging = productionRequest.isAutoStaging(); + String quicklookOutputDir = getOutputPath(productionRequest, productionId, ""); return new Production(productionId, productionName, - "", + quicklookOutputDir, stagingDir, autoStaging, productionRequest, workflowItem); } - // TODO, at the moment no staging implemented - @Override - protected Staging createUnsubmittedStaging(Production production) { - throw new UnsupportedOperationException("Staging currently not implemented for quick look generation."); - } - WorkflowItem createWorkflowItem(String productionId, String productionName, ProductionRequest productionRequest) throws ProductionException { diff --git a/calvalus-snap/pom.xml b/calvalus-snap/pom.xml index a9a5e031c..7da296f57 100644 --- a/calvalus-snap/pom.xml +++ b/calvalus-snap/pom.xml @@ -82,12 +82,6 @@ org.esa.snapsnap-watermask org.esa.snapsnap-sta - - ncsa.hdfjhdfobj - ncsa.hdfjhdf4obj - ncsa.hdfjhdf5obj - ncsa.hdflib-hdf - org.esa.s3tbxs3tbx-alos-reader org.esa.s3tbxs3tbx-atsr-reader org.esa.s3tbxs3tbx-avhrr-reader @@ -140,26 +134,6 @@ jetspeed-unpack-maven-plugin 2.2.2 - - libs - - - ncsa.hdf:lib-hdf:jar - - - lib/amd64 - libjhdf*.so - - - target/snap-bundle - - true - - package - - unpack - - libs2 @@ -182,26 +156,11 @@ - - ncsa.hdf - lib-hdf - ${ncsa.version} - org.esa.s2tbx lib-openjpeg ${snap.version} - - ncsa.hdf - jhdfobj - 2.7 - - - ncsa.hdf - jhdf5obj - 2.7 -