55import com .intellij .openapi .components .ServiceManager ;
66import com .intellij .openapi .diagnostic .Logger ;
77import com .intellij .openapi .project .Project ;
8+ import com .intellij .util .containers .ContainerUtil ;
89import org .jetbrains .plugins .github .api .GithubApiRequest ;
910import org .jetbrains .plugins .github .api .GithubApiRequestExecutor ;
1011import org .jetbrains .plugins .github .api .GithubApiRequestExecutorManager ;
1112import org .jetbrains .plugins .github .authentication .accounts .GithubAccount ;
1213
13- import javax .xml .bind .annotation .XmlTransient ;
1414import java .io .IOException ;
15+ import java .util .ArrayList ;
1516import java .util .List ;
1617import java .util .Map ;
17- import java .util .concurrent .ConcurrentHashMap ;
18+ import java .util .concurrent .atomic . AtomicReference ;
1819
1920public class GistSnippetService {
2021 public static final Logger logger = Logger .getInstance (GistSnippetService .class );
@@ -24,11 +25,9 @@ public class GistSnippetService {
2425 public static final String STARRED_GISTS_URL = "https://api.github.com/gists/starred" ;
2526 public static final String GIST_DETAIL_URL = "https://api.github.com/gists/%s" ;
2627
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 ();
3231
3332 public static GistSnippetService getInstance () {
3433 return ServiceManager .getService (GistSnippetService .class );
@@ -38,52 +37,85 @@ public static GistSnippetService getInstance() {
3837 public List <GistDTO > queryOwnGist (GithubAccount account , boolean forced ) {
3938 String key = account .toString () + "#own" ;
4039 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 );
4742 }
4843
49- return scopeCache .computeIfAbsent (key , (k ) -> {
44+ AtomicReference <List <GistDTO >> result = new AtomicReference <>();
45+ List <String > idList = scopeCache .computeIfAbsent (key , (k ) -> {
5046 try {
5147 GithubApiRequest .Get .JsonList request = new GithubApiRequest .Get .JsonList (OWN_GISTS_URL , GistDTO .class , MIME_TYPE );
5248 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 );
5552 } catch (IOException e ) {
5653 logger .info ("Failed to query own gist, error: " + e .getMessage ());
5754 notifyWarn ("Failed to load own Gist, " + e .getMessage (), null );
5855 return null ;
5956 }
6057 });
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 ();
6193 }
6294
6395 // queryStarredGist
6496 public List <GistDTO > queryStarredGist (GithubAccount account , boolean forced ) {
6597 String key = account .toString () + "#starred" ;
6698 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 );
73101 }
74102
75- return scopeCache .computeIfAbsent (key , (k ) -> {
103+ AtomicReference <List <GistDTO >> result = new AtomicReference <>();
104+ List <String > list = scopeCache .computeIfAbsent (key , (k ) -> {
76105 try {
77106 GithubApiRequest .Get .JsonList <GistDTO > request = new GithubApiRequest .Get .JsonList <>(STARRED_GISTS_URL , GistDTO .class , MIME_TYPE );
78107 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 );
81111 } catch (IOException e ) {
82112 logger .info ("Failed to query starred gist, error: " + e .getMessage ());
83113 notifyWarn ("Failed to load starred Gist, " + e .getMessage (), null );
84114 return null ;
85115 }
86116 });
117+
118+ return decideResult (account , result , list );
87119 }
88120
89121 // queryPublicGist
0 commit comments