Permessi in scrittura su infrastruttura Amazon Beanstalk (PHP)

In questa breve guida vedremo come è possibile modificare i permessi di accesso alle istanze EC2 configurate all’interno di un cluster Beanstalk. Potrebbe capitarvi, come nel mio caso, di voler lavorare su Beanstalk con un solo nodo (per esempio per sviluppare su un ambiente che sia il più simile possibile a quello di produzione) e che, essendo automaticamente configurato come macchina del cluster, segue una serie di regole dettate dal configuratore stesso per cui risulta non modificabile.

Annotiamo l’indirizzo ip del nodo, colleghiamoci in SSH e, avviata la console, digitiamo due semplici comandi:

sudo usermod -G webapp ec2-user
sudo chmod -R 775 /var/www/html/

Finito! A partire da questo momento, utilizzando il vostro client di sviluppo (Atom, Sublime etc.) con le dovute impostazioni per l’accesso tramite SFTP, potete creare e modificare file presenti nella directory WWWROOT del web server!

Attenzione: questo processo va eseguito ogni volta che aggiornate l’ambiente effettuando nuovi deploy della vostra app, infatti questo processo azzera e configura nuovamente l’istanza EC2!

Ricevere notifiche per onPause e onResume utilizzando React-Native su Android

Potrebbe capitarvi di utilizzare React-Native su piattaforma Android e di dover necessariamente gestire la vostra App in situazioni limite come, per esempio, l’uscita momentanea (onPause) e la riattivazione successiva alla chiusura (onResume).

Pur non presentando alcun metodo nativo (JS) che consenta di accedere al controllo dello stato dell’applicazione, React-Native offre tutti gli strumenti necessari per poter gestire tale casistica senza troppi problemi.

La soluzione è un modulo nativo personalizzato che si aggancia agli eventi del dispositivo e funge da mediatore tra il contesto Javascript e il processo dell’applicazione nativa consentendo la ricezione di notifiche rispetto al cambiamento di stato dell’app (messa in pausa o ripresa).

Per prima cosa dobbiamo realizzare una classe Java che lavori come modulo React-Native:

public class DeviceEventsModule 
  extends ReactContextBaseJavaModule implements LifecycleEventListener {

  @Override 
  public void onHostResume() {
    sendEvent("onResume");
  }

  @Override
  public void onHostPause() {
    sendEvent("onPause");
  }

  @Override
  public void onHostDestroy() {
    sendEvent("onDestroy");
  }

  private void sendEvent(String eventName) {
    // ... TO BE ... 
  }
}

L’oggetto realizzato estende la classe base ReactContextBaseJavaModule e implementa l’interfaccia LifecycleEventListener. L’utilizzo dell’interfaccia LifecycleEventListener richiede l’implementazione dei metodi onHostResume, onHostPause e onHostDestroy. Questi sono metodi invocati in corrispondenza degli eventi sopracitati. In ognuno di questi eventi ho aggiunto la chiamata ad un ulteriore metodo, sendEvent, di cui vi ripropongo di seguito l’implementazione:

private void sendEvent(String eventName) {
  ReactApplicationContext appContext = getReactApplicationContext();
  appContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
    .emit(eventName, null);
}

Questo non fa altro che attivare una comunicazione con l’oggetto react preposto all’inoltro delle notifiche al thread JS e, quando invocato, invia una notifica dell’evento specificato eventName.

Ora è necessario rendere disponibile questo modulo all’interno della nostra applicazione, sotto forma di modulo JS, questo lo si fa realizzando un ReactPackage:

public class AppPackage implements ReactPackage {
  @Override 
  public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
    return Arrays.<NativeModule>asList(new DeviceEventsModule(reactContext));
  }
}

Successivamente è opportuno registrare il pacchetto all’avvio dell’applicazione, all’interno dell’oggetto MainApplication, andando a modificare il metodo getPackages:

@Override
protected List<ReactPackage> getPackages() {
  return Arrays.asList(
    new MainReactPackage(),
    new AppPackage()
  );
}

Terminato lo sviluppo nativo, possiamo finalmente integrate, all’interno della nostra app, la gestione degli eventi di sospensione e ripresa dell’applicazione come mostrato in questo esempio:

import { 
  NativeModules
} from 'react-native';
let DeviceEvents = NativeModules.DeviceEvents;

class App extends React.Component {
  componentDidMount() {
    this.onPauseListener = DeviceEvents.addListener('onPause', () => {
      console.warn('Suspending app...');
      // La tua logica di sospensione qui!
    });
    this.onResumeListener = DeviceEvents.addListener('onResume', () => {
      console.warn('Resuming app...');
      // La tua logica di ripresa qui!
    });
  }
  componentWillUnmount() {
    // E' importante stoppare i listener quando il componente
    // è distrutto da React.
    this.onPauseListener.remove();
    this.onResumeListener.remove();
  }
}

L’esempio riportato inizializza i Listener nella fase di creazione del componente e li distrugge nella fase di distruzione dello stesso. Nel momento in cui l’app va in pausa o viene ripresa successivamente alla sospensione, riceviamo notifica di questo cambio di stato attraverso il nostro modulo personalizzato.

Questa guida si basa sulla documentazione tecnica disponibile ai seguenti link:

Caricare immagini da file system in React-Native

Immaginate di avere accesso ad un set di informazioni, tra le quali, figura il percorso fisico di un’immagine, presente sul dispositivo Smartphone, che dovete caricare all’interno della vostra applicazione. Normalmente siamo abituati ad utilizzare l’oggetto Image di React-Native con immagini locali, cioè presenti all’interno del nostro progetto, oppure con URI che puntano a file remoti (probabilmente sul web), come in questi esempi:

// Local project image:
<Image source={require('../assets/images/close.png') />

// Remote image: 
<Image source={{ uri: 'http://robertoconterosito.com/close.png' }} />

Cosa fare invece se l’immagine è proprio sul nostro dispositivo?
Se per esempio, abbiamo la necessità di mostrare la seguente immagine:

var localFile = '/data/user/temp/close.png'

E’ davvero questione di dettagli ma, come sempre, è fondamentale saperlo, in caso contrario la situazione è comunque complicata!
In questo caso, se utilizzassimo require non riusciremmo ad ottenere nulla, l’accorgimento da adottare invece è davvero semplice:

<Image source={{ uri: "file://" + localFile }} />

Aggiungendo come prefisso file:// costringiamo React ad attivarsi perché carichi l’immagine dallo storage locale e non più da un percorso remoto o relativo (interno alla nostra app).

Mappare una risposta JSON con nomi differenti su Android

Supponiamo di voler convertire la seguente risposta JSON in un oggetto Java le cui proprietà hanno un nome differente da quello specificato nella risposta HTTP (situazione tipica nei progetti in cui lavoro):

{ "nome": "Roberto", "cognome": "Conte Rosito", "età": "16" }

Utilizzando Jackson è possibile mappare la risposta in questo modo:

class Person {

  @JsonProperty("nome")
  private String name;

  @JsonProperty("cognome")
  private String surname;

  @JsonProperty("età")
  private String age;

  // ... Getter & Setter ... 
}

Apriamo il file build.gradle e aggiungiamo i riferimenti necessari:

dependencies {
  // ... Other deps ...
  compile (
    [group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.4.1'],
    [group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.4.1'],
    [group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.4.1']
  )
}

Successivamente, all’interno del nostro progetto, possiamo convertire la risposta in un oggetto di tipo Person (avendo precedentemente realizzato la classe) utilizzando queste istruzioni:

  String jsonResponse = ... ;
  ObjectMapper objectMapper = new ObjectMapper();
  Person personObject = objectMapper.readValue(jsonResponse, Person.class);

Ogni campo dell’oggetto marcato con l’annotazione @JsonProperty sarà processato secondo le direttive specificate all’interno dello stesso, in questo caso appunto il nome da utilizzare per la mappatura che dovrà essere diverso da quello utilizzato per dichiarare il campo all’interno del codice Java.

Filtrare una ListView in Android

Forse è l’operazione più comune con cui abbiamo a che fare quando dobbiamo gestire una ListView nelle nostre applicazioni Android. Farlo non è poi cosi complicato, anzi, lo stesso sistema operativo ci facilità il compito fornendo tutti gli strumenti necessari per poter realizzare tale funzionalità.

In questa guida vedremo come è possibile applicare un filtro su una lista. Per farlo ho pensato di non utilizzare il classico esempio, array di stringhe, ma di gestire una lista di oggetti complessi (niente di cosi complicato).

Supponiamo di voler caricare e filtrare un elenco di “Contatti”, ognuno dei quali è cosi composto:

class Contact {
  private String name;
  private String surname;
  private String value;
  // ... Getter & Setter ...

  public boolean containsText(String keyword) {
    if (keyword == null || keyword.isEmpty()) {
      return true;
    }
    if (name.toLowerCase().contains(keyword)) {
      return true;
    }
    if (surname.toLowerCase().contains(keyword)) {
      return true;
    }
    if (value.contains(keyword)) {
      return true;
    }
    return false;
  }
}

Nel codice riportato è presente un metodo, containsText, che ci tornerà utile nei passaggi successivi per l’applicazione dei filtri. Per prima cosa dobbiamo realizzare un ArrayAdapter che ci consenta di gestire i dati da presentare all’interno della lista:

class ContactListViewAdapter extends ArrayAdapter<Contact> {
  private List mOriginalData;
  private List mFilteredData;
  public ContactListViewAdapter(Context context, int resource, List list) {
    super(context, resource, list);
    mOriginalData = list;
    mFilteredData = list;
  }
  
  @Override
  public int getCount() {
    return mFilteredData.size();
  }
  
  @Override
  public Contact getItem(int position) {
    return mFilteredData.get(position);
  }

  @Override
  public long getItemId(int position) {
    return position;
  } 
  
  @NonNull
  @Override
  public View getView(int position, final View convertView, ViewGroup parent) {
    // ... Render ...
  }
}

Nell’esempio riportato è stato effettuato l’override di alcuni metodi poiché, come è possibile notare dallo stesso codice, l’adapter realizzato riporta due List di contatti, la prima è la lista originale dei dati, mOriginalData, la seconda rappresenta quella filtrata, appunto mFilteredData. L’adapter prenderà come riferimento sempre l’elenco filtrato per caricare i contatti all’interno della ListView.

Cosi com’è ora, la lista non consente l’effettiva applicazione del filtro, ci manca ancora un passaggio, cioè la realizzazione del Filter, l’oggetto che a regime ci consentirà di applicare un criterio di ricerca e aggiornare l’elenco dei risultati. Per farlo dobbiamo modificare la classe ContactListViewAdapter aggiungendo un ulteriore dettaglio:

class ContactListViewAdapter implements ArrayAdapter extends Filterable {
  private class ItemFilter extends Filter {
    @Override
    protected Filter.FilterResults performFiltering(CharSequence constraint) {
      String filterString = constraint != null ? constraint.toString() : "";
      FilterResults results = new FilterResults();
      final List list = originalData;
      int count = list.size();
      final ArrayList<Contact> outputList = new ArrayList<>(count);
      Contact c;
      for (int i = 0; i < count; i++) {
        c = list.get(i);
        if (c.containsText(filterString)) {
          outputList.add(filterableEBook);
        }
      }

      results.values = outputList;
      results.count = outputList.size();

      return results;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
      filteredData = (ArrayList<EBook>)results.values;
      notifyDataSetChanged();
    }

 }   
 
 // Aggiungo un nuovo campo nell'adapter:
 private ItemFilter mItemFilter = new ItemFilter();

 // Eseguo l'override del metodo preposto per l'applicazione dei filtri:
 @Override
 public Filter getFilter() {
   return mItemFilter;
 }
 // Proprietà precedentemente mostrate ... 
}

In pratica ciò che abbiamo fatto ora è implementare l’interfaccia Filterable che, successivamente, ci consente di applicare un filtro sulla nostra lista con estrema facilità. Utilizzando il metodo containsText presente nell’oggetto Contact, verifichiamo il match tra chiave di ricerca e contatto stesso per capire se deve o meno essere mostrato all’interno dei risultati.

Di seguito un esempio di codice con cui poter testare il risultato:

List<Contact> data= new ArrayList<>();
contactList.add(new Contact() {{
  setName("Roberto");
  setSurname("Conte Rosito");
  setValue("roberto.conterosito@gmail.com");
}});
contactList.add(new Contact() {{
  setName("Mario");
  setSurname("Rossi");
  setValue("mario.rossi@gmail.com");
}});
contactList.add(new Contact() {{
  setName("Mark");
  setSurname("Zuck");
  setValue("mark@facebook.com");
}});
mListViewAdapter = new ContactListViewAdapter(getBaseContext(), R.layout.item, data);
mListView = (ListView)findViewById(R.id.list);
mListView.setAdapter(mListViewAdapter);
postDelayed(new Runnable() {
  @Override
  public void run() {
    // Dopio 10 secondi vedremo comparire i soli contatti 
    // che hanno indirizzo Gmail!
    mListView.getFilter().filter("@gmail.com");
  }
}, 10 * 1000);

L’esempio riportato carica la lista e, dopo un tempo minimo di attesa (per simulare un esempio), applica un filtro che mostra i soli contatti che rispettano il criterio di ricerca specificato.

Caricare un file javascript embedded da una libreria in un progetto ASP.NET MVC

Appunto qui per ricordarmene in futuro visto che ultimamente dimentico tutto: ho realizzato una libreria di classi in cui, oltre ad oggetti C#, sono presenti diversi file javascript il cui contenuto è necessario perché le classi possano funzionare correttamente. Per caricarli all’interno del progetto principale è necessario:

  1. selezionare il file javascript presente nel progetto libreria;
  2. dal menu contestuale (click destro del mouse), selezionare la voce Proprietà;
  3. nella finestra che compare modificare Build Action: Embedded Resource.
  4. nel file AssemblyInfo.cs della del progetto libreria aggiungere una nuova riga di codice:
[assembly:System.Web.UI.WebResource(
  "YourNamespace.Resource.js", 
  "application/x-javascript"
)]

A questo punto possiamo caricare il file javascript utilizzando ClientScript.GetWebResourceUrl(Type, resourceName).
Utilizzando ASP.NET MVC è necessario un ulteriore passaggio perché tutto funzioni correttamente: realizzare una classe che ci consenta di reperire direttamente l’URL del file javascript da poter includere nella nostra pagina web:

public static class ResLocator
{
  private const string UrlLocatorMethodName = "GetWebResourceUrlInternal";
  public static string Resolve(Type assemblyObjectType, string resourceName) 
  {
    MethodInfo resourceLocatorMethod = assemblyObjectType.GetMethod(UrlLocatorMethodName, 
    BindingFlags.NonPublic | BindingFlags.Static);
    string url = string.Format("/{0}", resourceLocatorMethod.Invoke(
      null,
      new object[] { Assembly.GetAssembly(assemblyObjectType), resourcePath, false })
    );
    return url;
  }
}

Il metodo Resolve accetta in input un Type che deve necessariamente riferirsi ad un tipo di oggetto contenuto nel progetto libreria e resourceName, cioè il nome della risorsa da includere. Successivamente, referenziando il namespace in cui è contenuto l’helper all’interno della nostra MasterPage, è possibile includere lo script di riferimento in questo modo:

<script 
  type="text/javascript" 
  src="@ResLocator.Resolve(typeof(SampleAssemblyObject), "YourNamespace.Resource.js)" />

Completati questi passaggi è possibile avviare l’app MVC e ottenere un URL simile al seguente:

/WebResource.axd?d=HWyLh7g77XD...Z81&t=634788092174760080

Formato vecchio o libreria di tipo non valido con PIAs

Un problema che si potrebbe incontrare durante l’utilizzo di oggetti Microsoft.Interop.Office.Excel e l’impossibilità di poter esportare file, blocco dovuto ad un particolare messaggio di errore:

Formato vecchio o libreria di tipo non valido. (Exception from HRESULT: 0×80028018 (TYPE_E_INVDATAREAD)).

Questo errore, all’interno di applicazioni web, è dovuto ad una differenza di Cultura tra la versione di Microsoft Office installata sul server (differente appunto da quella del web server stesso). La soluzione al problema è molto semplice, durante l’esecuzione di operazioni che richiamano oggetti Excel è necessario cambiare, sul web server, il contesto di esecuzione, impostando una cultura (definita principalmente dalla lingua stessa) uguale a quella della versione di Microsoft Office installata.

Per prima cosa apriamo il file web.config, posizioniamoci nella sezione appSettings e scriviamo:

<add key="CultureInfo" value="it-IT" />

Successivamente realizziamo una semplice classe che ci consente di applicare uno switch, istantaneamente, sulla lingua del Thread in esecuzione:

public class MsCultureSwitch : IDisposable
{
  public static string CultureInfoName
  {
      get { return ConfigurationManager.AppSettings["CultureInfo"]; }
  }
  
  private CultureInfo originalCulture = null;

  public MsCultureSwitch()
  {
    originalCulture = Thread.CurrentThread.CurrentCulture;
    Thread.CurrentThread.CurrentCulture = new CultureInfo(CultureInfoName);
  }

  public void Dispose()
  {
    Thread.CurrentThread.CurrentCulture = originalCulture;
  }
}

Infine possiamo utilizzare l’oggetto appena creato per eseguire codice con la libreria PIAs:

using(MsCultureSwitch msCulture = new MsCultureSwitch())
{
  // Here your PIAs Code!
}

Finito! Spero possa tornare utile anche a voi!