Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 20 additions & 32 deletions api/src/org/labkey/api/data/CachedResultSetBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import org.labkey.api.collections.ResultSetRowMapFactory;
import org.labkey.api.collections.RowMap;
import org.labkey.api.data.ResultSetMetaDataImpl.ColumnMetaData;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
Expand All @@ -39,25 +40,36 @@ public static FromResultSet create(ResultSet rs)
return new FromResultSet(rs);
}

public static FromListOfMaps create(List<Map<String, Object>> maps)
public static FromListOfMaps create(List<Map<String, Object>> maps, ResultSetMetaData md)
{
return create(maps, maps.get(0).keySet());
return new FromListOfMaps(maps, md);
}

/**
* Create CachedResultSetBuilder from a list of maps and collection of column names. For the most flexibility, the
* maps may need to be case-insensitive. How do you tell? If the maps have data and the keys match the columnNames,
* but the ResultSet rowMap values are all null.
* @param maps List of row data, possibly case-insensitive maps
* @param columnNames Collection of column names
* @param columns Collection of ColumnInfos populated with name and JdbcType at a minimum
*
* TODO: A case-insensitive option for the builder, but there may be performance impact for very large result sets
* if the implementation were simply to wrap each incoming map with CaseInsensitiveHashMap. For now, onus is on the
* caller to provide case insensitive maps when necessary.
*/
public static FromListOfMaps create(List<Map<String, Object>> maps, Collection<String> columnNames)
public static FromListOfMaps create(List<Map<String, Object>> maps, Collection<? extends ColumnInfo> columns)
{
return new FromListOfMaps(maps, columnNames);
ResultSetMetaDataImpl md = new ResultSetMetaDataImpl(columns.size());

for (ColumnInfo column : columns)
{
ColumnMetaData col = new ColumnMetaData();
col.columnName = column.getColumnName();
col.columnLabel = column.getColumnName();
col.columnType = column.getJdbcType().sqlType;
md.addColumn(col);
}

return create(maps, md);
}

public abstract C getThis();
Expand Down Expand Up @@ -133,15 +145,14 @@ public CachedResultSet build() throws SQLException
public final static class FromListOfMaps extends CachedResultSetBuilder<FromListOfMaps>
{
private final List<Map<String, Object>> _maps;
private final Collection<String> _columnNames;
private final ResultSetMetaData _md;

private ResultSetMetaData _md = null;
private boolean _isComplete = true;

private FromListOfMaps(List<Map<String, Object>> maps, Collection<String> columnNames)
private FromListOfMaps(List<Map<String, Object>> maps, ResultSetMetaData md)
{
_maps = maps;
_columnNames = columnNames;
_md = md;
}

@Override
Expand All @@ -150,12 +161,6 @@ public FromListOfMaps getThis()
return this;
}

public FromListOfMaps setMetaData(ResultSetMetaData md)
{
_md = md;
return this;
}

public FromListOfMaps setComplete(boolean complete)
{
_isComplete = complete;
Expand All @@ -164,27 +169,10 @@ public FromListOfMaps setComplete(boolean complete)

public CachedResultSet build()
{
if (_md == null)
_md = createMetaData(_columnNames);

return new CachedResultSet(_md, convertToRowMaps(_md, _maps), _isComplete, _requireClose, _stackTrace);
}
}

private static ResultSetMetaData createMetaData(Collection<String> columnNames)
{
ResultSetMetaDataImpl md = new ResultSetMetaDataImpl(columnNames.size());
for (String columnName : columnNames)
{
ResultSetMetaDataImpl.ColumnMetaData col = new ResultSetMetaDataImpl.ColumnMetaData();
col.columnName = columnName;
col.columnLabel = columnName;
md.addColumn(col);
}

return md;
}

private static ArrayList<RowMap<Object>> convertToRowMaps(ResultSetMetaData md, List<Map<String, Object>> maps)
{
ArrayList<RowMap<Object>> list = new ArrayList<>();
Expand Down
13 changes: 0 additions & 13 deletions api/src/org/labkey/api/data/DataRegion.java
Original file line number Diff line number Diff line change
Expand Up @@ -2593,19 +2593,6 @@ private void renderOldValues(HtmlWriter out, Map<String, Object> valueMap, Map<F
renderOldValues(out, map);
}


public static List<ColumnInfo> colInfosFromMetaData(ResultSetMetaData md) throws SQLException
{
int columnCount = md.getColumnCount();
List<ColumnInfo> cols = new LinkedList<>();

for (int i = 1; i <= columnCount; i++)
cols.add(new BaseColumnInfo(md, i));

return cols;
}


/**
* Render the data region. All rendering SHOULD go through this function
* public renderForm, renderTable methods actually all go through here
Expand Down
3 changes: 2 additions & 1 deletion api/src/org/labkey/api/view/Portal.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
*/
public class Portal implements ModuleChangeListener
{
private static final Logger LOG = LogHelper.getLogger(Portal.class, "Page and web part warnings");
private static final Logger LOG = LogHelper.getLogger(Portal.class, "Page and web part warnings and exceptions");
private static final WebPartBeanLoader FACTORY = new WebPartBeanLoader();

public static final String FOLDER_PORTAL_PAGE = "folder";
Expand Down Expand Up @@ -1714,6 +1714,7 @@ public static WebPartView getWebPartViewSafe(@NotNull WebPartFactory factory, @N
WebPartView<?> errorView;
if (t instanceof HttpStatusException)
{
LOG.debug("Exception while rendering a webpart", t);
BindException errors = new BindException(new Object(), "form");
errors.reject(SpringActionController.ERROR_MSG, t.getMessage());
errorView = new SimpleErrorView(errors, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
import org.labkey.api.data.CachedResultSetBuilder;
import org.labkey.api.data.ColumnInfo;
import org.labkey.api.data.DataRegion;
import org.labkey.api.data.JdbcType;
import org.labkey.api.data.RenderContext;
import org.labkey.api.data.ResultsImpl;
import org.labkey.api.data.RuntimeSQLException;
import org.labkey.api.data.SimpleDisplayColumn;
import org.labkey.api.pipeline.PipeRoot;
import org.labkey.api.pipeline.PipelineJobService;
Expand All @@ -42,7 +42,6 @@
import org.springframework.validation.BindException;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
Expand Down Expand Up @@ -71,7 +70,6 @@ public ProtocolManagementWebPart(ViewContext viewContext)
super(new DataRegion(), (BindException) null);
setViewContext(viewContext);
setTitle(NAME);
createResults();
getDataRegion().setSettings(new QuerySettings(getViewContext(), NAME));
getDataRegion().setSortable(false);
getDataRegion().setShowFilters(false);
Expand All @@ -81,6 +79,9 @@ public ProtocolManagementWebPart(ViewContext viewContext)
getDataRegion().setShowRecordSelectors(true);
}
getDataRegion().setRecordSelectorValueColumns("taskId", "name");

// Create results last since some statements above could throw on bad input, causing us to abandon an unclosed Results
createResults();
}

private ButtonBar createButtonBar()
Expand All @@ -101,27 +102,24 @@ private ButtonBar createButtonBar()
private void createResults() // Accept filter & sort ? Tough to use standard UI components the way this is wired in.
{
List<Map<String, Object>> rows = getProtocols().stream().map(Protocol::toMap).collect(Collectors.toList());
ResultSet rs = CachedResultSetBuilder.create(rows, Arrays.asList("taskId", "name", "pipeline", "archived")).build();
try
{
List<ColumnInfo> colInfos = DataRegion.colInfosFromMetaData(rs.getMetaData());

Map<String, String> params = new HashMap<>();
params.put("taskId", "taskId");
params.put("name", "name");
params.put("archived", "archived");
ActionURL actionURL = new ActionURL(AnalysisController.ProtocolDetailsAction.class, getViewContext().getContainer());
DetailsURL url = new DetailsURL(actionURL.addReturnUrl(getContextURLHelper()), params);
((BaseColumnInfo)colInfos.get(1)).setURL(url);
setResults(new ResultsImpl(rs, colInfos));
getDataRegion().setColumns(colInfos);
getDataRegion().getDisplayColumn("taskId").setVisible(false);
getDataRegion().replaceDisplayColumn("archived", new ArchivedDisplayColumn());
}
catch (SQLException e)
{
throw new RuntimeSQLException(e);
}
List<ColumnInfo> colInfos = List.of(
new BaseColumnInfo("taskId", JdbcType.VARCHAR),
new BaseColumnInfo("name", JdbcType.VARCHAR),
new BaseColumnInfo("pipeline", JdbcType.VARCHAR),
new BaseColumnInfo("archived", JdbcType.BOOLEAN)
);
ResultSet rs = CachedResultSetBuilder.create(rows, colInfos).build();
Map<String, String> params = new HashMap<>();
params.put("taskId", "taskId");
params.put("name", "name");
params.put("archived", "archived");
ActionURL actionURL = new ActionURL(AnalysisController.ProtocolDetailsAction.class, getViewContext().getContainer());
DetailsURL url = new DetailsURL(actionURL.addReturnUrl(getContextURLHelper()), params);
((BaseColumnInfo)colInfos.get(1)).setURL(url);
setResults(new ResultsImpl(rs, colInfos));
getDataRegion().setColumns(colInfos);
getDataRegion().getDisplayColumn("taskId").setVisible(false);
getDataRegion().replaceDisplayColumn("archived", new ArchivedDisplayColumn());
}

private List<Protocol> getProtocols()
Expand Down