List of usage examples for org.apache.commons.lang3 StringUtils abbreviate
public static String abbreviate(final String str, final int maxWidth)
Abbreviates a String using ellipses.
From source file:ubic.gemma.core.loader.expression.arrayDesign.ArrayDesignSequenceProcessingServiceImpl.java
/** * Replace information in "existing" with data from "found". *//*from w w w. j av a 2s.c om*/ private BioSequence updateExistingWithSequenceData(BioSequence found, BioSequence existing) { assert found != null; assert existing != null; if (existing.getType() == null) existing.setType(found.getType()); // generic... existing.setLength(found.getLength()); assert found.getSequence() != null; existing.setSequence(found.getSequence()); existing.setIsApproximateLength(found.getIsApproximateLength()); if (existing.getSequenceDatabaseEntry() == null) { ArrayDesignSequenceProcessingServiceImpl.log .debug("Inserting database entry into existing sequence " + existing); existing.setSequenceDatabaseEntry(found.getSequenceDatabaseEntry()); } // This is just for debugging purposes -- some array designs give suspicious sequence information. if (existing.getSequence().length() > 10e4) { ArrayDesignSequenceProcessingServiceImpl.log .warn(existing + " - new sequence is very long for an expression probe (" + existing.getSequence().length() + " bases)"); } bioSequenceService.update(existing); if (ArrayDesignSequenceProcessingServiceImpl.log.isDebugEnabled()) ArrayDesignSequenceProcessingServiceImpl.log.debug( "Updated " + existing + " with sequence " + StringUtils.abbreviate(existing.getSequence(), 20)); assert found.getSequenceDatabaseEntry().getExternalDatabase() != null; return existing; }
From source file:ubic.gemma.core.loader.expression.geo.GeoConverterImpl.java
/** * Turn a rough-cut dimension name into something of reasonable length. *///from w w w .jav a2 s.c o m private String formatName(StringBuilder dimensionName) { return StringUtils.abbreviate(dimensionName.toString(), 100); }
From source file:ubic.gemma.persistence.service.analysis.expression.diff.DifferentialExpressionResultDaoImpl.java
@Override public Map<Long, Map<Long, DiffExprGeneSearchResult>> findDiffExAnalysisResultIdsInResultSets( Collection<DiffExResultSetSummaryValueObject> resultSets, Collection<Long> geneIds) { Map<Long, Map<Long, DiffExprGeneSearchResult>> results = new HashMap<>(); Session session = this.getSessionFactory().getCurrentSession(); Map<Long, DiffExResultSetSummaryValueObject> resultSetIdsMap = EntityUtils.getIdMap(resultSets, "getResultSetId"); Map<Long, Collection<Long>> foundInCache = this.fillFromCache(results, resultSetIdsMap.keySet(), geneIds); if (!foundInCache.isEmpty()) { AbstractDao.log.info("Results for " + foundInCache.size() + " resultsets found in cache"); } else {//w ww . ja v a2 s. c o m AbstractDao.log.info("No results were in the cache"); } Collection<Long> resultSetsNeeded = this.stripUnneededResultSets(foundInCache, resultSetIdsMap.keySet(), geneIds); // Are we finished? if (resultSetsNeeded.isEmpty()) { AbstractDao.log.info("All results were in the cache."); return results; } AbstractDao.log.info(foundInCache.size() + "/" + resultSetIdsMap.size() + " resultsSets had at least some cached results; still need to query " + resultSetsNeeded.size()); assert !resultSetsNeeded.isEmpty(); org.hibernate.SQLQuery queryObject = session.createSQLQuery( DifferentialExpressionResultDaoImpl.fetchBatchDifferentialExpressionAnalysisResultsByResultSetsAndGeneQuery); /* * These values have been tweaked to probe for performance issues. */ int resultSetBatchSize = 50; int geneBatchSize = 100; if (resultSetsNeeded.size() > geneIds.size()) { resultSetBatchSize = Math.min(500, resultSetsNeeded.size()); AbstractDao.log.info("Batching by result sets (" + resultSetsNeeded.size() + " resultSets); " + geneIds.size() + " genes; batch size=" + resultSetBatchSize); } else { geneBatchSize = Math.min(200, geneIds.size()); AbstractDao.log.info("Batching by genes (" + geneIds.size() + " genes); " + resultSetsNeeded.size() + " resultSets; batch size=" + geneBatchSize); } final int numResultSetBatches = (int) Math.ceil(resultSetsNeeded.size() / resultSetBatchSize); queryObject.setFlushMode(FlushMode.MANUAL); StopWatch timer = new StopWatch(); timer.start(); int numResults = 0; long timeForFillingNonSig = 0; Map<Long, Map<Long, DiffExprGeneSearchResult>> resultsFromDb = new HashMap<>(); int numResultSetBatchesDone = 0; // Iterate over batches of resultSets for (Collection<Long> resultSetIdBatch : new BatchIterator<>(resultSetsNeeded, resultSetBatchSize)) { if (AbstractDao.log.isDebugEnabled()) AbstractDao.log.debug("Starting batch of resultsets: " + StringUtils.abbreviate(StringUtils.join(resultSetIdBatch, ","), 100)); /* * Get the probes using the CommonQueries gene2cs. Otherwise we (in effect) end up doing this over and over * again. */ Map<Long, Collection<Long>> cs2GeneIdMap = this.getProbesForGenesInResultSetBatch(session, geneIds, resultSetIdsMap, resultSetIdBatch); queryObject.setParameterList("rs_ids", resultSetIdBatch); int numGeneBatchesDone = 0; final int numGeneBatches = (int) Math.ceil(cs2GeneIdMap.size() / geneBatchSize); StopWatch innerQt = new StopWatch(); // iterate over batches of probes (genes) for (Collection<Long> probeBatch : new BatchIterator<>(cs2GeneIdMap.keySet(), geneBatchSize)) { if (AbstractDao.log.isDebugEnabled()) AbstractDao.log.debug("Starting batch of probes: " + StringUtils.abbreviate(StringUtils.join(probeBatch, ","), 100)); // would it help to sort the probeBatch/ List<Long> pbL = new Vector<>(probeBatch); Collections.sort(pbL); queryObject.setParameterList("probe_ids", pbL); innerQt.start(); List<?> queryResult = queryObject.list(); innerQt.stop(); if (innerQt.getTime() > 2000) { // show the actual query with params. AbstractDao.log.info("Query time: " + innerQt.getTime() + "ms:\n " + queryObject.getQueryString().replace(":probe_ids", StringUtils.join(probeBatch, ",")) .replace(":rs_ids", StringUtils.join(resultSetIdBatch, ","))); } innerQt.reset(); /* * Each query tuple are the probe, result, resultsSet, qvalue, pvalue. */ for (Object o : queryResult) { // Long resultSetId = ( ( BigInteger )((Object[])o)[2] ).longValue(); // if (!resultSetId.equals) numResults += this.processResultTuple(o, resultsFromDb, cs2GeneIdMap); } if (timer.getTime() > 5000 && AbstractDao.log.isInfoEnabled()) { AbstractDao.log.info("Batch time: " + timer.getTime() + "ms; Fetched DiffEx " + numResults + " results so far. " + numResultSetBatchesDone + "/" + numResultSetBatches + " resultset batches completed. " + numGeneBatchesDone + "/" + numGeneBatches + " gene batches done."); timer.reset(); timer.start(); } // Check if task was cancelled. if (Thread.currentThread().isInterrupted()) { throw new TaskCancelledException("Search was cancelled"); } numGeneBatchesDone++; if (DifferentialExpressionResultDaoImpl.CORRECTED_PVALUE_THRESHOLD_TO_BE_CONSIDERED_DIFF_EX < 1.0) { timeForFillingNonSig += this.fillNonSignificant(pbL, resultSetIdsMap, resultsFromDb, resultSetIdBatch, cs2GeneIdMap, session); } } // over probes. // Check if task was cancelled. if (Thread.currentThread().isInterrupted()) { throw new TaskCancelledException("Search was cancelled"); } numResultSetBatchesDone++; } if (timer.getTime() > 1000 && AbstractDao.log.isInfoEnabled()) { AbstractDao.log.info("Fetching DiffEx from DB took total of " + timer.getTime() + " ms : geneIds=" + StringUtils.abbreviate(StringUtils.join(geneIds, ","), 50) + " result set=" + StringUtils.abbreviate(StringUtils.join(resultSetsNeeded, ","), 50)); if (timeForFillingNonSig > 100) { AbstractDao.log.info("Filling in non-significant values: " + timeForFillingNonSig + "ms in total"); } } // Add the DB results to the cached results. this.addToCache(resultsFromDb, resultSetsNeeded, geneIds); for (Long resultSetId : resultsFromDb.keySet()) { Map<Long, DiffExprGeneSearchResult> geneResults = resultsFromDb.get(resultSetId); if (results.containsKey(resultSetId)) { results.get(resultSetId).putAll(geneResults); } else { results.put(resultSetId, geneResults); } } return results; }
From source file:ubic.gemma.persistence.service.genome.biosequence.BioSequenceDaoImpl.java
private void debug(BioSequence query, List<?> results) { StringBuilder sb = new StringBuilder(); sb.append("\nMultiple BioSequences found matching query:\n"); if (query != null) { sb.append("\tQuery: ID=").append(query.getId()).append(" Name=").append(query.getName()); if (StringUtils.isNotBlank(query.getSequence())) sb.append(" Sequence=").append(StringUtils.abbreviate(query.getSequence(), 10)); if (query.getSequenceDatabaseEntry() != null) sb.append(" acc=").append(query.getSequenceDatabaseEntry().getAccession()); sb.append("\n"); }//from ww w. j a v a2s . c o m for (Object object : results) { BioSequence entity = (BioSequence) object; sb.append("\tMatch: ID=").append(entity.getId()).append(" Name=").append(entity.getName()); if (StringUtils.isNotBlank(entity.getSequence())) sb.append(" Sequence=").append(StringUtils.abbreviate(entity.getSequence(), 10)); if (entity.getSequenceDatabaseEntry() != null) sb.append(" acc=").append(entity.getSequenceDatabaseEntry().getAccession()); sb.append("\n"); } if (AbstractDao.log.isDebugEnabled()) AbstractDao.log.debug(sb.toString()); }
From source file:ubic.gemma.persistence.util.monitor.HibernateMonitorImpl.java
@Override public String getStats(boolean showEntityStats, boolean showCollectionStats, boolean showSecondLevelCacheDetails) { Statistics stats = sessionFactory.getStatistics(); StringBuilder buf = new StringBuilder(); buf.append("Statistics started at: ").append(new Date(stats.getStartTime())).append("\n"); long flushes = stats.getFlushCount(); long trans = stats.getTransactionCount(); long prep = stats.getPrepareStatementCount(); long open = stats.getSessionOpenCount(); long close = stats.getSessionCloseCount(); long ex = stats.getQueryExecutionCount(); buf.append("Queries executed: ").append(ex).append("\n"); buf.append(open).append(" sessions opened, ").append(close).append(" closed\n"); buf.append(prep).append(" statements prepared, ").append(trans).append(" transactions completed, ") .append(flushes).append(" flushes.\n"); String slowQuery = stats.getQueryExecutionMaxTimeQueryString(); long queryExecutionMaxTime = stats.getQueryExecutionMaxTime(); if (queryExecutionMaxTime > 1000) { buf.append("Slowest query [").append(queryExecutionMaxTime).append("ms]: ") .append(StringUtils.abbreviate(slowQuery, 150)).append("\n"); }//from w w w .jav a 2 s . com buf.append("\n------------------- Query Cache stats -----------------------\n"); long queryCacheHitCount = stats.getQueryCacheHitCount(); long queryCacheMissCount = stats.getQueryCacheMissCount(); long queryCachePutCount = stats.getQueryCachePutCount(); buf.append("Puts: ").append(queryCachePutCount).append("\n"); buf.append("Hits: ").append(queryCacheHitCount).append("\n"); buf.append("Misses: ").append(queryCacheMissCount).append("\n"); buf.append("\n------------------- Second Level Cache stats -----------------------\n"); long secCacheHits = stats.getSecondLevelCacheHitCount(); long secCacheMiss = stats.getSecondLevelCacheMissCount(); long secCachePut = stats.getSecondLevelCachePutCount(); buf.append("Puts: ").append(secCachePut).append("\n"); buf.append("Hits: ").append(secCacheHits).append("\n"); buf.append("Misses: ").append(secCacheMiss).append("\n"); if (showSecondLevelCacheDetails) { String[] regions = stats.getSecondLevelCacheRegionNames(); Arrays.sort(regions); for (String region : regions) { SecondLevelCacheStatistics secondLevelCacheStatistics = stats.getSecondLevelCacheStatistics(region); long hitCount = secondLevelCacheStatistics.getHitCount(); long missCount = secondLevelCacheStatistics.getMissCount(); long putCount = secondLevelCacheStatistics.getPutCount(); long size = secondLevelCacheStatistics.getSizeInMemory(); long count = secondLevelCacheStatistics.getElementCountInMemory(); long diskCount = secondLevelCacheStatistics.getElementCountOnDisk(); if (putCount > 0 || hitCount > 0 || missCount > 0) { buf.append(region).append(": ").append(hitCount).append(" hits; ").append(missCount) .append(" misses; ").append(putCount).append(" puts; Memcount=").append(count) .append("; Diskcount=").append(diskCount).append(" MemSizeBytes=").append(size) .append("\n"); } } } if (showCollectionStats) { buf.append("\n------------------- Collection stats -----------------------\n"); String[] collectionRoleNames = stats.getCollectionRoleNames(); Arrays.sort(collectionRoleNames); for (String string : collectionRoleNames) { CollectionStatistics collectionStatistics = stats.getCollectionStatistics(string); long fetchCount = collectionStatistics.getFetchCount(); long loadCount = collectionStatistics.getLoadCount(); long updateCount = collectionStatistics.getUpdateCount(); if (fetchCount > 0 || loadCount > 0 || updateCount > 0) { buf.append(string).append(": ").append(fetchCount).append(" fetches, ").append(loadCount) .append(" loads, ").append(updateCount).append(" updates\n"); } } } if (showEntityStats) { buf.append("\n------------------- Entity stats -----------------------\n"); String[] entityNames = stats.getEntityNames(); Arrays.sort(entityNames); for (String string : entityNames) { EntityStatistics entityStats = stats.getEntityStatistics(string); long changes = entityStats.getInsertCount() + entityStats.getUpdateCount() + entityStats.getDeleteCount(); if (changes > 0) { String shortName; try { shortName = Class.forName(string).getSimpleName().replaceFirst("Impl", ""); buf.append(shortName).append(" updates: ").append(changes).append(" \n"); } catch (ClassNotFoundException e) { HibernateMonitorImpl.log.error(e, e); } } long reads = entityStats.getLoadCount(); if (reads > 0) { String shortName; try { shortName = Class.forName(string).getSimpleName().replaceFirst("Impl", ""); buf.append(shortName).append(" read: ").append(reads).append(" \n"); } catch (ClassNotFoundException e) { HibernateMonitorImpl.log.error(e, e); } } } } return buf.toString(); }
From source file:ubic.gemma.web.controller.common.CharacteristicBrowserController.java
/** * @param avo//from ww w .j av a 2 s . co m * @param annotatedItem - the object that has the annotation, we want to find who "owns" it. */ private void populateParentInformation(AnnotationValueObject avo, Object annotatedItem) { assert avo != null; if (annotatedItem == null) { avo.setParentLink( "[Parent hidden or not available, " + avo.getObjectClass() + " ID=" + avo.getId() + "]"); } else if (annotatedItem instanceof ExpressionExperiment) { ExpressionExperiment ee = (ExpressionExperiment) annotatedItem; avo.setParentName(String.format("Experiment: %s", ee.getName())); avo.setParentLink(AnchorTagUtil.getExpressionExperimentLink(ee.getId(), avo.getParentName())); } else if (annotatedItem instanceof BioMaterial) { BioMaterial bm = (BioMaterial) annotatedItem; avo.setParentName(String.format("BioMat: %s", bm.getName())); avo.setParentLink(AnchorTagUtil.getBioMaterialLink(bm.getId(), avo.getParentName())); ExpressionExperiment ee = expressionExperimentService.findByBioMaterial(bm); if (ee == null) { log.warn("Expression experiment for " + bm + " was null"); return; } avo.setParentOfParentName(String.format("%s", ee.getName())); // avo.setParentOfParentDescription( ee.getDescription() ); avo.setParentOfParentLink( AnchorTagUtil.getExpressionExperimentLink(ee.getId(), avo.getParentOfParentName())); } else if (annotatedItem instanceof FactorValue) { FactorValue fv = (FactorValue) annotatedItem; avo.setParentDescription(String.format("FactorValue: %s « Exp.Factor: %s", (fv.getValue() == null ? "" : ": " + fv.getValue()), fv.getExperimentalFactor().getName())); ExpressionExperiment ee = expressionExperimentService.findByFactorValue(fv); if (ee == null) { log.warn("Expression experiment for " + fv + " was null"); return; } avo.setParentOfParentName(String.format("Experimental Design for: %s", ee.getName())); avo.setParentOfParentLink(AnchorTagUtil.getExperimentalDesignLink( fv.getExperimentalFactor().getExperimentalDesign().getId(), avo.getParentName()) + " « " + AnchorTagUtil.getExpressionExperimentLink(ee.getId(), String.format("%s (%s)", StringUtils.abbreviate(ee.getName(), 80), ee.getShortName()))); } else if (annotatedItem instanceof ExperimentalFactor) { ExperimentalFactor ef = (ExperimentalFactor) annotatedItem; avo.setParentLink(AnchorTagUtil.getExperimentalDesignLink(ef.getExperimentalDesign().getId(), "Exp Fac: " + ef.getName() + " (" + StringUtils.abbreviate(ef.getDescription(), 50) + ")")); ExpressionExperiment ee = experimentalDesignService.getExpressionExperiment(ef.getExperimentalDesign()); if (ee == null) { log.warn("Expression experiment for " + ef + " was null"); return; } avo.setParentOfParentName( String.format("%s (%s)", StringUtils.abbreviate(ee.getName(), 80), ee.getShortName())); avo.setParentOfParentLink( AnchorTagUtil.getExpressionExperimentLink(ee.getId(), avo.getParentOfParentName())); } else if (annotatedItem instanceof PhenotypeAssociation) { PhenotypeAssociation pa = (PhenotypeAssociation) annotatedItem; avo.setParentLink("PhenotypeAssoc: " + pa.getGene().getOfficialSymbol()); avo.setParentDescription(pa.getId().toString()); } }
From source file:ubic.gemma.web.controller.common.HomePageController.java
/** * For the show-off graph that shows number of data sets per taxon. *///w ww. j ava2 s . c om public void getCountsForTaxonPieChart() { Map<Taxon, Long> unsortedEEsPerTaxon = expressionExperimentService.getPerTaxonCount(); /* * Sort taxa by count. */ TreeSet<Map.Entry<Taxon, Long>> eesPerTaxonValueSorted = new TreeSet<Map.Entry<Taxon, Long>>( new TaxonComparator()); eesPerTaxonValueSorted.addAll(unsortedEEsPerTaxon.entrySet()); long expressionExperimentCount = expressionExperimentService.countAll(); double groupBelow = 0.1; // if a taxon has less then this percent of total count, group into 'other' String googleData = encodeDataForGoogle(eesPerTaxonValueSorted.descendingSet(), expressionExperimentCount, groupBelow); List<String> googleLabelsColls = new ArrayList<String>(); boolean grouped = false; List<String> others = new ArrayList<String>(); for (Entry<Taxon, Long> entry : eesPerTaxonValueSorted.descendingSet()) { String tname = entry.getKey().getCommonName(); if (StringUtils.isBlank(tname)) tname = entry.getKey().getScientificName(); if (entry.getValue() == 0) continue; if (groupIntoOther(entry.getValue(), expressionExperimentCount, groupBelow)) { grouped = true; others.add(tname); } else { googleLabelsColls.add(tname); } } if (grouped) { googleLabelsColls.add(StringUtils.abbreviate(StringUtils.join(others, ", "), 50)); } String googleLabels = StringUtils.join(googleLabelsColls, '|'); mav.addObject("googleData", googleData); mav.addObject("googleLabels", googleLabels); }
From source file:ubic.gemma.web.controller.diff.DifferentialExpressionSearchController.java
/** * AJAX entry.//from w ww. j a v a 2 s . co m * Value objects returned contain experiments that have 2 factors and have had the diff analysis run on it. */ public Collection<ExpressionExperimentExperimentalFactorValueObject> getFactors(final Collection<Long> eeIds) { Collection<ExpressionExperimentExperimentalFactorValueObject> result = new HashSet<>(); final Collection<Long> securityFilteredIds = securityFilterExpressionExperimentIds(eeIds); if (securityFilteredIds.size() == 0) { return result; } log.debug("Getting factors for experiments with ids: " + StringUtils.abbreviate(securityFilteredIds.toString(), 100)); Collection<Long> filteredEeIds = new HashSet<>(); Map<Long, Collection<DifferentialExpressionAnalysis>> diffAnalyses = differentialExpressionAnalysisService .findByInvestigationIds(securityFilteredIds); if (diffAnalyses.isEmpty()) { log.debug("No differential expression analyses for given ids: " + StringUtils.join(filteredEeIds, ',')); return result; } Collection<ExpressionExperimentValueObject> eevos = this.expressionExperimentService .loadValueObjects(diffAnalyses.keySet(), false); Map<Long, ExpressionExperimentValueObject> eevoMap = new HashMap<>(); for (ExpressionExperimentValueObject eevo : eevos) { eevoMap.put(eevo.getId(), eevo); } for (Long id : diffAnalyses.keySet()) { Collection<DifferentialExpressionAnalysis> analyses = diffAnalyses.get(id); for (DifferentialExpressionAnalysis analysis : analyses) { differentialExpressionAnalysisService.thaw(analysis); Collection<ExperimentalFactor> factors = new HashSet<>(); for (FactorAssociatedAnalysisResultSet fars : analysis.getResultSets()) { // FIXME includes factors making up interaction terms, but shouldn't // matter, because they will be included as main effects too. If not, this will be wrong! factors.addAll(fars.getExperimentalFactors()); } filteredEeIds.add(id); ExpressionExperimentValueObject eevo = eevoMap.get(id); ExpressionExperimentExperimentalFactorValueObject eeefvo = new ExpressionExperimentExperimentalFactorValueObject(); eeefvo.setExpressionExperiment(eevo); eeefvo.setNumFactors(factors.size()); for (ExperimentalFactor ef : factors) { ExperimentalFactorValueObject efvo = geneDifferentialExpressionService .configExperimentalFactorValueObject(ef); eeefvo.getExperimentalFactors().add(efvo); } result.add(eeefvo); } } log.info("Filtered experiments. Returning factors for experiments with ids: " + StringUtils.abbreviate(filteredEeIds.toString(), 100)); return result; }
From source file:ubic.gemma.web.controller.expression.experiment.DesignMatrixRowValueObject.java
/** * @param factor factor// ww w . jav a 2 s . com * @return A unique string for the factor, but hopefully human-readable. */ private String getFactorString(ExperimentalFactor factor) { if (StringUtils.isBlank(factor.getDescription()) || factor.getDescription().equals(factor.getName())) { return factor.getName(); } // Note: the use of stringUtils.abbreviate here can cause json parsing problems for DWR, due to the '...', and // no means of escaping seems to fix this. String result = factor.getName() + " (" + StringUtils.abbreviate(factor.getDescription(), 25).replace("...", "") + ")"; if (factorValueMap.containsKey(result)) { result = result + " [" + factor.getId() + "]"; } return result; }
From source file:ubic.gemma.web.controller.expression.experiment.ExpressionExperimentQCController.java
/** * Support method for writeDetailedFactorAnalysis * * @param categories map of factor ID to text value. Strings will be unique, but possibly abbreviated and/or munged. */// w w w . jav a 2 s . com private void getCategories(Map<Long, ExperimentalFactor> efIdMap, Long efId, Map<Long, String> categories) { ExperimentalFactor ef = efIdMap.get(efId); if (ef == null) return; int maxCategoryLabelLength = 10; for (FactorValue fv : ef.getFactorValues()) { String value = fv.getValue(); if (StringUtils.isBlank(value) || value.equals("null")) { for (Characteristic c : fv.getCharacteristics()) { if (StringUtils.isNotBlank(c.getValue())) { if (StringUtils.isNotBlank(value)) { value = value + "; " + c.getValue(); } else { value = c.getValue(); } } } } if (StringUtils.isBlank(value)) { value = fv.toString() + "--??"; } if (value.startsWith(ExperimentalDesignUtils.BATCH_FACTOR_NAME_PREFIX)) { value = value.replaceFirst(ExperimentalDesignUtils.BATCH_FACTOR_NAME_PREFIX, ""); } else { value = StringUtils.abbreviate(value, maxCategoryLabelLength); } while (categories.values().contains(value)) { value = value + "+";// make unique, kludge, will end up with string of ++++ } categories.put(fv.getId(), value); } }