5
5
import com .intellij .openapi .components .ServiceManager ;
6
6
import com .intellij .openapi .diagnostic .Logger ;
7
7
import com .intellij .openapi .project .Project ;
8
+ import com .intellij .util .containers .ContainerUtil ;
8
9
import org .jetbrains .plugins .github .api .GithubApiRequest ;
9
10
import org .jetbrains .plugins .github .api .GithubApiRequestExecutor ;
10
11
import org .jetbrains .plugins .github .api .GithubApiRequestExecutorManager ;
11
12
import org .jetbrains .plugins .github .authentication .accounts .GithubAccount ;
12
13
13
- import javax .xml .bind .annotation .XmlTransient ;
14
14
import java .io .IOException ;
15
+ import java .util .ArrayList ;
15
16
import java .util .List ;
16
17
import java .util .Map ;
17
- import java .util .concurrent .ConcurrentHashMap ;
18
+ import java .util .concurrent .atomic . AtomicReference ;
18
19
19
20
public class GistSnippetService {
20
21
public static final Logger logger = Logger .getInstance (GistSnippetService .class );
@@ -24,11 +25,9 @@ public class GistSnippetService {
24
25
public static final String STARRED_GISTS_URL = "https://api.github.com/gists/starred" ;
25
26
public static final String GIST_DETAIL_URL = "https://api.github.com/gists/%s" ;
26
27
27
- // Just cache in memory
28
- @ XmlTransient
29
- private Map <String , List <GistDTO >> scopeCache = new ConcurrentHashMap <>();
30
- @ XmlTransient
31
- private Map <String , GistDTO > gistCache = new ConcurrentHashMap <>();
28
+ // cache in memory, can be collected
29
+ private Map <String , List <String >> scopeCache = ContainerUtil .createConcurrentSoftValueMap ();
30
+ private Map <String , GistDTO > gistCache = ContainerUtil .createConcurrentSoftValueMap ();
32
31
33
32
public static GistSnippetService getInstance () {
34
33
return ServiceManager .getService (GistSnippetService .class );
@@ -38,52 +37,85 @@ public static GistSnippetService getInstance() {
38
37
public List <GistDTO > queryOwnGist (GithubAccount account , boolean forced ) {
39
38
String key = account .toString () + "#own" ;
40
39
if (forced ) {
41
- List <GistDTO > gistDTOS = scopeCache .computeIfPresent (key , (k , v ) -> scopeCache .remove (k ));
42
- if (gistDTOS != null ) {
43
- for (GistDTO gistDTO : gistDTOS ) {
44
- gistCache .remove (gistDTO .getId ());
45
- }
46
- }
40
+ List <String > gists = scopeCache .computeIfPresent (key , (k , v ) -> scopeCache .remove (k ));
41
+ removeFromCache (gists );
47
42
}
48
43
49
- return scopeCache .computeIfAbsent (key , (k ) -> {
44
+ AtomicReference <List <GistDTO >> result = new AtomicReference <>();
45
+ List <String > idList = scopeCache .computeIfAbsent (key , (k ) -> {
50
46
try {
51
47
GithubApiRequest .Get .JsonList request = new GithubApiRequest .Get .JsonList (OWN_GISTS_URL , GistDTO .class , MIME_TYPE );
52
48
GithubApiRequestExecutor executor = GithubApiRequestExecutorManager .getInstance ().getExecutor (account );
53
- List <GistDTO > result = (List <GistDTO >) executor .execute (request );
54
- return result ;
49
+ List <GistDTO > gistList = (List <GistDTO >) executor .execute (request );
50
+ result .set (gistList );
51
+ return putIntoCache (gistList );
55
52
} catch (IOException e ) {
56
53
logger .info ("Failed to query own gist, error: " + e .getMessage ());
57
54
notifyWarn ("Failed to load own Gist, " + e .getMessage (), null );
58
55
return null ;
59
56
}
60
57
});
58
+
59
+ return decideResult (account , result , idList );
60
+ }
61
+
62
+ private void removeFromCache (List <String > gists ) {
63
+ if (gists != null ) {
64
+ for (String gistId : gists ) {
65
+ gistCache .remove (gistId );
66
+ }
67
+ }
68
+ }
69
+
70
+ private List <String > putIntoCache (List <GistDTO > gistList ) {
71
+ if (gistList != null ) {
72
+ List <String > list = new ArrayList <>(gistList .size ());
73
+ for (GistDTO gistDTO : gistList ) {
74
+ list .add (gistDTO .getId ());
75
+ gistCache .putIfAbsent (gistDTO .getId (), gistDTO );
76
+ }
77
+ return list ;
78
+ }
79
+ return null ;
80
+ }
81
+
82
+ private List <GistDTO > decideResult (GithubAccount account , AtomicReference <List <GistDTO >> result , List <String > idList ) {
83
+ if (result .get () == null && idList != null ) {
84
+ // N + 1
85
+ List <GistDTO > gistList = new ArrayList <>(idList .size ());
86
+ for (String gistId : idList ) {
87
+ gistList .add (getGistDetail (account , gistId , false ));
88
+ }
89
+ result .set (gistList );
90
+ }
91
+
92
+ return result .get ();
61
93
}
62
94
63
95
// queryStarredGist
64
96
public List <GistDTO > queryStarredGist (GithubAccount account , boolean forced ) {
65
97
String key = account .toString () + "#starred" ;
66
98
if (forced ) {
67
- List <GistDTO > gistDTOS = scopeCache .computeIfPresent (key , (k , v ) -> scopeCache .remove (k ));
68
- if (gistDTOS != null ) {
69
- for (GistDTO gistDTO : gistDTOS ) {
70
- gistCache .remove (gistDTO .getId ());
71
- }
72
- }
99
+ List <String > gists = scopeCache .computeIfPresent (key , (k , v ) -> scopeCache .remove (k ));
100
+ removeFromCache (gists );
73
101
}
74
102
75
- return scopeCache .computeIfAbsent (key , (k ) -> {
103
+ AtomicReference <List <GistDTO >> result = new AtomicReference <>();
104
+ List <String > list = scopeCache .computeIfAbsent (key , (k ) -> {
76
105
try {
77
106
GithubApiRequest .Get .JsonList <GistDTO > request = new GithubApiRequest .Get .JsonList <>(STARRED_GISTS_URL , GistDTO .class , MIME_TYPE );
78
107
GithubApiRequestExecutor executor = GithubApiRequestExecutorManager .getInstance ().getExecutor (account );
79
- List <GistDTO > result = (List <GistDTO >) executor .execute (request );
80
- return result ;
108
+ List <GistDTO > gistList = (List <GistDTO >) executor .execute (request );
109
+ result .set (gistList );
110
+ return putIntoCache (gistList );
81
111
} catch (IOException e ) {
82
112
logger .info ("Failed to query starred gist, error: " + e .getMessage ());
83
113
notifyWarn ("Failed to load starred Gist, " + e .getMessage (), null );
84
114
return null ;
85
115
}
86
116
});
117
+
118
+ return decideResult (account , result , list );
87
119
}
88
120
89
121
// queryPublicGist
0 commit comments