22
33import java .io .FileWriter ;
44import java .io .IOException ;
5- import java .io .InputStream ;
65import java .io .Writer ;
76import java .nio .file .Files ;
87import java .nio .file .Path ;
98import java .time .LocalDate ;
10- import java .util .ArrayList ;
119import java .util .List ;
12- import java .util .Optional ;
1310import java .util .regex .Pattern ;
1411import java .util .stream .Collectors ;
1512
2219import org .jabref .logic .importer .OpenDatabase ;
2320import org .jabref .logic .importer .ParseException ;
2421import org .jabref .logic .importer .SearchBasedFetcher ;
25- import org .jabref .logic .importer .fileformat .BibtexParser ;
2622import org .jabref .model .database .BibDatabase ;
2723import org .jabref .model .database .BibDatabaseContext ;
28- import org .jabref .model .entry .BibEntry ;
2924import org .jabref .model .entry .BibEntryTypesManager ;
30- import org .jabref .model .entry .field .UnknownField ;
31- import org .jabref .model .entry .types .SystematicLiteratureReviewStudyEntryType ;
3225import org .jabref .model .study .FetchResult ;
26+ import org .jabref .model .study .LibraryEntry ;
27+ import org .jabref .model .study .QueryEntry ;
3328import org .jabref .model .study .QueryResult ;
3429import org .jabref .model .study .Study ;
3530import org .jabref .model .util .FileUpdateMonitor ;
4843 */
4944class StudyRepository {
5045 // Tests work with study.bib
51- private static final String STUDY_DEFINITION_FILE_NAME = "study.bib " ;
46+ private static final String STUDY_DEFINITION_FILE_NAME = "study.yml " ;
5247 private static final Logger LOGGER = LoggerFactory .getLogger (StudyRepository .class );
5348 private static final Pattern MATCHCOLON = Pattern .compile (":" );
5449 private static final Pattern MATCHILLEGALCHARACTERS = Pattern .compile ("[^A-Za-z0-9_.\\ s=-]" );
5550
5651 private final Path repositoryPath ;
57- private final Path studyDefinitionBib ;
52+ private final Path studyDefinitionFile ;
5853 private final GitHandler gitHandler ;
5954 private final Study study ;
6055 private final ImportFormatPreferences importFormatPreferences ;
@@ -81,13 +76,13 @@ public StudyRepository(Path pathToRepository, GitHandler gitHandler, ImportForma
8176 }
8277 this .importFormatPreferences = importFormatPreferences ;
8378 this .fileUpdateMonitor = fileUpdateMonitor ;
84- this .studyDefinitionBib = Path .of (repositoryPath .toString (), STUDY_DEFINITION_FILE_NAME );
79+ this .studyDefinitionFile = Path .of (repositoryPath .toString (), STUDY_DEFINITION_FILE_NAME );
8580 this .savePreferences = savePreferences ;
8681 this .bibEntryTypesManager = bibEntryTypesManager ;
8782
8883 if (Files .notExists (repositoryPath )) {
8984 throw new IOException ("The given repository does not exists." );
90- } else if (Files .notExists (studyDefinitionBib )) {
85+ } else if (Files .notExists (studyDefinitionFile )) {
9186 throw new IOException ("The study definition file does not exist in the given repository." );
9287 }
9388 study = parseStudyFile ();
@@ -116,30 +111,39 @@ public BibDatabaseContext getStudyResultEntries() throws IOException {
116111 }
117112
118113 /**
119- * The study definition file contains all the definitions of a study. This method extracts the BibEntries from the study BiB file.
114+ * The study definition file contains all the definitions of a study. This method extracts this study from the yaml study definition file
120115 *
121116 * @return Returns the BibEntries parsed from the study definition file.
122117 * @throws IOException Problem opening the input stream.
123118 * @throws ParseException Problem parsing the study definition file.
124119 */
125- private Study parseStudyFile () throws IOException , ParseException {
126- BibtexParser parser = new BibtexParser (importFormatPreferences , fileUpdateMonitor );
127- List <BibEntry > parsedEntries = new ArrayList <>();
128- try (InputStream inputStream = Files .newInputStream (studyDefinitionBib )) {
129- parsedEntries .addAll (parser .parseEntries (inputStream ));
130- }
120+ private Study parseStudyFile () throws IOException {
121+ return new StudyYAMLParser ().parseStudyYAMLFile (studyDefinitionFile );
122+ }
123+
124+ /**
125+ * Returns all query strings of the study definition
126+ *
127+ * @return List of all queries as Strings.
128+ */
129+ public List <String > getSearchQueryStrings () {
130+ return study .getQueries ()
131+ .parallelStream ()
132+ .map (QueryEntry ::getQuery )
133+ .collect (Collectors .toList ());
134+ }
131135
132- BibEntry studyEntry = parsedEntries . parallelStream ()
133- . filter ( bibEntry -> bibEntry . getType (). equals ( SystematicLiteratureReviewStudyEntryType . STUDY_ENTRY )). findAny ()
134- . orElseThrow (() -> new ParseException ( "Study definition file does not contain a study entry" ));
135- List < BibEntry > queryEntries = parsedEntries . parallelStream ()
136- . filter ( bibEntry -> bibEntry . getType (). equals ( SystematicLiteratureReviewStudyEntryType . SEARCH_QUERY_ENTRY ))
137- . collect ( Collectors . toList ());
138- List <BibEntry > libraryEntries = parsedEntries . parallelStream ()
139- . filter ( bibEntry -> bibEntry . getType (). equals ( SystematicLiteratureReviewStudyEntryType . LIBRARY_ENTRY ) )
140- . collect ( Collectors . toList ());
141-
142- return new Study ( studyEntry , queryEntries , libraryEntries );
136+ /**
137+ * Extracts all active fetchers from the library entries.
138+ *
139+ * @return List of BibEntries of type Library
140+ * @throws IllegalArgumentException If a transformation from Library entry to LibraryDefinition fails
141+ */
142+ public List <LibraryEntry > getActiveLibraryEntries () throws IllegalArgumentException {
143+ return study . getLibraries ( )
144+ . parallelStream ()
145+ . filter ( LibraryEntry :: isEnabled )
146+ . collect ( Collectors . toList () );
143147 }
144148
145149 public Study getStudy () {
@@ -163,16 +167,16 @@ public void persist(List<QueryResult> crawlResults) throws IOException, GitAPIEx
163167 }
164168
165169 private void persistStudy () throws IOException {
166- writeResultToFile ( studyDefinitionBib , new BibDatabase ( study . getAllEntries ()) );
170+ new StudyYAMLParser (). writeStudyYAMLFile ( study , studyDefinitionFile );
167171 }
168172
169173 /**
170174 * Create for each query a folder, and for each fetcher a bib file in the query folder to store its results.
171175 */
172176 private void setUpRepositoryStructure () throws IOException {
173177 // Cannot use stream here since IOException has to be thrown
174- LibraryEntryToFetcherConverter converter = new LibraryEntryToFetcherConverter (study .getActiveLibraryEntries (), importFormatPreferences );
175- for (String query : study .getSearchQueryStrings ()) {
178+ LibraryEntryToFetcherConverter converter = new LibraryEntryToFetcherConverter (this .getActiveLibraryEntries (), importFormatPreferences );
179+ for (String query : this .getSearchQueryStrings ()) {
176180 createQueryResultFolder (query );
177181 converter .getActiveFetchers ()
178182 .forEach (searchBasedFetcher -> createFetcherResultFile (query , searchBasedFetcher ));
@@ -229,14 +233,14 @@ private void createBibFile(Path file) {
229233 * Structure: ID-trimmed query
230234 *
231235 * Examples:
232- * Input: '(title: test-title AND abstract: Test)' as a query entry with id 1
233- * Output: '1 - title= test-title AND abstract= Test'
236+ * Input: '(title: test-title AND abstract: Test)' as a query entry with id 12345678
237+ * Output: '12345678 - title= test-title AND abstract= Test'
234238 *
235- * Input: 'abstract: Test*' as a query entry with id 1
236- * Output: '1 - abstract= Test'
239+ * Input: 'abstract: Test*' as a query entry with id 87654321
240+ * Output: '87654321 - abstract= Test'
237241 *
238- * Input: '"test driven"' as a query entry with id 1
239- * Output: '1 - test driven'
242+ * Input: '"test driven"' as a query entry with id 12348765
243+ * Output: '12348765 - test driven'
240244 *
241245 * @param query that is trimmed and combined with its query id
242246 * @return a unique folder name for any query.
@@ -245,31 +249,20 @@ private String trimNameAndAddID(String query) {
245249 // Replace all field: with field= for folder name
246250 String trimmedNamed = MATCHCOLON .matcher (query ).replaceAll ("=" );
247251 trimmedNamed = MATCHILLEGALCHARACTERS .matcher (trimmedNamed ).replaceAll ("" );
248- if (query .length () > 240 ) {
249- trimmedNamed = query .substring (0 , 240 );
252+ String id = computeIDForQuery (query );
253+ // Whole path has to be shorter than 260
254+ int remainingPathLength = 220 - studyDefinitionFile .toString ().length () - id .length ();
255+ if (query .length () > remainingPathLength ) {
256+ trimmedNamed = query .substring (0 , remainingPathLength );
250257 }
251- String id = findQueryIDByQueryString (query );
252258 return id + " - " + trimmedNamed ;
253259 }
254260
255261 /**
256- * Helper to find the query id for folder name creation.
257- * Returns the id of the first SearchQuery BibEntry with a query field that matches the given query.
258- *
259- * @param query The query whose ID is searched
260- * @return ID of the query defined in the study definition.
262+ * Helper to compute the query id for folder name creation.
261263 */
262- private String findQueryIDByQueryString (String query ) {
263- String queryField = "query" ;
264- return study .getSearchQueryEntries ()
265- .parallelStream ()
266- .filter (bibEntry -> bibEntry .getField (new UnknownField (queryField )).orElse ("" ).equals (query ))
267- .map (BibEntry ::getCitationKey )
268- .filter (Optional ::isPresent )
269- .map (Optional ::get )
270- .findFirst ()
271- .orElseThrow ()
272- .replaceFirst (queryField , "" );
264+ private String computeIDForQuery (String query ) {
265+ return String .valueOf (query .hashCode ());
273266 }
274267
275268 /**
0 commit comments