|  | /* | 
|  | Copyright 2017 Google Inc. | 
|  |  | 
|  | Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | you may not use this file except in compliance with the License. | 
|  | You may obtain a copy of the License at | 
|  |  | 
|  | http://www.apache.org/licenses/LICENSE-2.0 | 
|  |  | 
|  | Unless required by applicable law or agreed to in writing, software | 
|  | distributed under the License is distributed on an "AS IS" BASIS, | 
|  | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | See the License for the specific language governing permissions and | 
|  | limitations under the License. | 
|  | */ | 
|  |  | 
|  | package adapter | 
|  |  | 
|  | import ( | 
|  | "encoding/json" | 
|  | "fmt" | 
|  | "net/http" | 
|  | "sync" | 
|  | "time" | 
|  |  | 
|  | "github.com/apid/istioApigeeAdapter/common" | 
|  | ) | 
|  |  | 
|  | const ( | 
|  | defaultProductsFetch = time.Minute | 
|  | ) | 
|  |  | 
|  | type productManager struct { | 
|  | fetchURL   string | 
|  | products   map[string]*common.APIProduct | 
|  | refresh    time.Duration | 
|  | expiration time.Time | 
|  | latch      *sync.Mutex | 
|  | } | 
|  |  | 
|  | func newProductManager(fetchURL string, refreshTime time.Duration) *productManager { | 
|  | return &productManager{ | 
|  | fetchURL: fetchURL, | 
|  | refresh:  refreshTime, | 
|  | latch:    &sync.Mutex{}, | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | getProducts returns the products that match a list of names. For now it is simple -- we will | 
|  | use a mutex and update the list when it's expired. In the future we can be fancier with | 
|  | periodic refresh. | 
|  | */ | 
|  | func (m *productManager) getProducts(names []string) ([]common.APIProduct, error) { | 
|  | m.latch.Lock() | 
|  | defer m.latch.Unlock() | 
|  |  | 
|  | if m.products == nil || m.expiration.Before(time.Now()) { | 
|  | err := m.fetchProductList() | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | } | 
|  |  | 
|  | var products []common.APIProduct | 
|  | for _, name := range names { | 
|  | p := m.products[name] | 
|  | if p != nil { | 
|  | products = append(products, *p) | 
|  | } | 
|  | } | 
|  | return products, nil | 
|  | } | 
|  |  | 
|  | func (m *productManager) fetchProductList() error { | 
|  | resp, err := http.Get(m.fetchURL) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | defer resp.Body.Close() | 
|  | if resp.StatusCode != 200 { | 
|  | return fmt.Errorf("HTTP error %d fetching API product list", resp.StatusCode) | 
|  | } | 
|  |  | 
|  | var pl common.APIProductResponse | 
|  | jr := json.NewDecoder(resp.Body) | 
|  | err = jr.Decode(&pl) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | m.products = make(map[string]*common.APIProduct) | 
|  | for _, p := range pl.Products { | 
|  | m.products[p.Name] = &p | 
|  | } | 
|  | m.expiration = time.Now().Add(m.refresh) | 
|  | return nil | 
|  | } |