neděle 3. března 2019

Birdhouse and Camera

My daughter received Christmas gift "a small birdhouse". Ive got an idea to install camera with motion detection for better capturing and documenting all feeding birds in our new birdhouse. As software developer, I bought computer called Raspberry Pie - famous, cheap, small and open computer. Edition "Raspberry Pie Zero", most cheaper and minimal power consumping computer looks very suitable for my purpose. Native support for camera is included.



The most difficult part of our "project" was to find good software solution for capturing video. I tried some common solutions, but it was terrible slow. My colleage Martin Šimek gave me an advice. "Try Pikrellcam". Its a small project for Raspberry Pi with very fast motion detection based on compression in video algorithm.

 Installation of birdhouse behind the windows as well as"dirty and temporar" installation of camera:


After some days, many kinds of birds were captured. I tried to find their names:

Sýkora koňadra (Parus major):

 Červenka obecná (Erithacus rubecula)

Brhlík lesní (Sitta europaea)
  

Sýkora modřinka (Cyanistes caeruleus)


Resources:
  • Raspberry Pi Zero : https://www.raspberrypi.org/products/raspberry-pi-zero/
  • Pikrellcam project : http://billw2.github.io/pikrellcam/pikrellcam.html   

úterý 4. září 2018

"Přihašte se do Vašeho bankovnictví na mém tabletu, prosím!"

Výjimečně jsem zašel na pobočku banky České spořitelny, abych vyřešil nějaké záležitosti. Jako pracovník IT rád řeším věci on-line. Dnes však mé návštěvě napomohly dvě věci. Jednak jsem nebyl schopen na portálu banky najít elektronický dokument pro daňové přiznání (ano, jsem ten šťastný chudák s takřka doživotní hypotékou a rád bych si pár korun odečetl na daních) a také jsem měl cestu kolem s trochou času nazbyt.

Ihned, jak jsem vešel dovnitř, na mne dýchl moderní vzhled celého interiéru. Asi po dvěstě letech zmizely tradiční přepážky. Né, že by na této pobočce ještě před měsícem byly paravány a stoly z leštěného dřeva z první republiky. Co si vzpomínám, tak zde byly poměrně moderní stoly ala současná kancelář z katalogu "openspace pro všechny". Teď však interiér dosáhl změn především v koncepci. Celý prostor byl kompletně předělán. Všechno působí moderně a decentně zároveň. Hned se mi na mysl derou slova jako "google", "apple".... trošku přeháním. Každopádně se jedná o velkou změnu tohoto celkem konzervativního bankovního domu. "Chudáci babičky, které byly celý život zvyklé na přepážky." pomyslím si a sám tápu, kam si vlastně sednu. Celému prostoru totiž dominuje jakýsi centrální kulatý stůl, u které si s pracovníkem banky nejspíš společně sedem. Atmosféra by podle všeho měla navozovat kamarádské a vlídné prostředí a vztah mezi klientem a bankou. No, uvidíme.





Tradičně u automatu obdržím pořadové číslo a jdu si počkat, než půjdu na řadu. Za nedlouho se objeví pracovnice banky ověšená notebookem, tabletem a nějakými papíry, tužkami, kalkulačkamy, pascím strojem:) (sotva to všcho pobere) se neobratně vydává ke kulatému stolu. Sotva se usadí, pokývne na mě. Jdu si k ní přisednout a v hlavě mi vznikají první kritické myšlenky nového look-and-feel prostředí. Evidentně si pracovník musí pro každého klienta tahat veškeré harampádí s sebou, neboť centrální kulatý stůl "rytířů svatého grálu" je vždy před a po odchodu klienta prázdný. Móda holt není vždy ergonomická.


Vyřizuji s paní svoje záležitosti a ptám se, kde se v internetovém bankovnictví nachází inkriminovaný dokument. "Tady máte tablet, přihlašte se svým účtem a já Vám ukážu, kde to najdete."...… Sedím trochu opařený. V mozku se mi honí všechny moderní poučky o internetové bezpečnosti. Slyším dobře? …. po dvou vteřinách ticha zdvořile odmítám s odůvodněním, že své přihlašovací údaje nebudu vkládat do neznámého zařízení. Pracovnici moje odpověď trochu překvapila, nicméně pro zachování celé ceremonie zdvořile nabídne moznost pracovat s DEMO prostředí portálu. Během přípravy ještě pronese, že se jedná o standardní postup, kdy se klient přihlašuje do tohoto společného zařízení bez větších problémů.
Uběhne asi týden a já mám pořád v hlavě nabídku pracovnice banky. Nedá mí to a rozhodu se sesmolit mail s dotazem na info schránku spořitelny.


Dobrý den,                                                                               19. 2. 2018 11:31
Před pár dny jsem šel řešit nějaké záležitosti na pobočku České spořitelny, Částkova 2215/50, Plzeň, 32600 Plzeň.
 

Překvapilo mne, že mi pracovnice pobočky nabídla tablet, abych se na něm přihlásil do svého internetového bankovnictví. Zdvořile jsem odmítl, protože to považuji za bezpečnostní riziko. 
Nezdá se mi správné, aby klient banky zadával přihlašovací údaje do takového přenosného zařízení, které může být poměrně snadno zkompromitováno (ať již zaměstnancem banky, nebo nějakým odborným klientem, který měl zařízení v ruce přede mnou). 
Chápu, že zařízení nejspíš patřilo bance a může být chráněno před instalací škodlivého software, přesto by klientovi neměla být tato možnost vůbec nabízena.
S pozdravem
 
Ing. David Kacetl
Plzeň
Vše je řečeno v mailu. Sám jsem zvědavý, jak se banka vyjádří. Pár dní na to přišla odpověď v papírové podobě.

Verze s vyšším rozlišením. Zajímavé. Zdvořilá, uctivá, sebemrskačská odpověď. Už vidím Lenku Nikodymovou, které přistálo moje hlášení na stole, jak telefonuje ajťákům na všechny strany a snaží se sesmolit politicky korektní vyjádření "aby se vlk nažral a koza zůstala celá". 

Chápu, že pracovník je určitým způsobem "polobůh" a může něco nekalého udělat, je jasné. Ovšem vždy bude (tedy jeho identita) zapsán v auditačním logu dané nekalé bankovní akce a lze tedy pachatele dohledat. Celé riziko spočívá přeci především v krádeži identity. To je ten důvod, proč se nemají zadávat přihlašovací údaje kamkoli. To je podstatou všech phishing útoků, krádeže facebookových a jiných účtů (o kterých nás denně informují nejen taková geniální média jako jsou TV Nova apod.). A jako obrana se pak používají generátory hesel zaslaných papírově poštou, různé dlouhé klíče, které nesmí znát ani pracovník banky (respektive může k ověření vyžadovat například jen část klíče - typicky 2 náhodné znaky při telefonickém ověření). 

Všechny tyto složité procedury pak smázne špatné použití tabletu v bezpečném přístavu bankovní instituce - na pobočce.   

Pokud tedy kdokoli - i pracovník banky - ukradne identitu klienta (jméno/heslo) - právě například pomocí tabletu - nic nebrání udělat neplechu, na kterou nikdo nepříjde.

Skvělé:) 

P.S. Celá věc se stala začátkem roku 2018, dále jsem se tím nezabýval, takže netuším, zda se udály nějaké změny či jestli šlo o ojedinělý případ. Každopádně zadávat přihlašovací údaje kamkoli včetně umaštěného tabletu paní na pobočce nedoporučuji a neschvaluji.

pondělí 10. července 2017

Oprava trafa akuvrtačky

Jednoho kráskného kutilského dne mi odešla moje low-cost akuvrtačka Einhell BT-CD 18 1h. Přesněji, odešla mi "jen" nabíječka, ale co dělat s vrtačkou a baterkama, když je nemůžete použít?


Protože jsem kutil s maturitou z elektroprůmyslovky a vrtačka velice dobře a dlouho sloužila, nechtel jsem se všeho jen tak zbavit a koupit novou. Byla tu možnost, že se jedná o drobnou poruchu, např. přepálená pojistka.

Rozebrání

Nabíječka má zespodu ctyři šrouby, je to v pohodě.... jenže: kdosi v nekonečné potřebě zabránit opravě tohoto zařízení, osadil výrobek jedním bezpečnostním šroubem. Šroub je jakousi mutací obvyklých šroubů. Není křížový, ani klasický, je něco mezi - má tvar "Y", tedy jakási trojcípá hvězda.

Už jsem se s tímto způsobem "zabezpečení" setkal. U naší low-cost mikrovlnky. nevím, kolik lidských životů bylo zachráněno díky zamezení neodborného vstupu pod dekl spotřebiče, rozhodně si troufnu říci, že tisíce tun opravitelných elektrozařízení skončilo na smetišti jen díky nemožnosti se dostat "dovnitř". Skvělá doba.

Nejdřív zkouším trochu násilí, jestli plast pod tímto humus-šroubkem nepovolí. Drží to jako skála. Sbírám po domě všechny druhy šroubováků a zkouším. Nakonec se povedlo šroub povolit a sundat jedním plochým tenkým šroubováčkem, který se správně zakousnul. Zabezpečí úspěšně hacknuto, jede se dál.


Průzkum plošného spoje

Musím uznat, že v jednoduchosti je síla. Zde mne mile překvapilo, že elektronika nabíječky - tedy plošný spoj, je "easy" zapojení z devadesátých let, tedy z dob mé platné maturitní zkoušky. Není zde žádný mega obvod zalitý v asfaltu. Naopak ze na první pohled najít usměrňovací můstek, filtrační kondenzátor, relátko, dal39 pasivní součástky a jeden integrovaný obvod, který s trochou štěstí, bude snad v pořádku.



Hledání poruchy

Nyní dochází k nejdůležitějšé části celé činnosti - nalezení místa poruchy. Podrobně prohlédů všechny součástky. Žádná nevykazuje zjevné požkození. Ani pojistka není přetavená.

Co teď? Nezbývá, než celou nabíječku oživit a multimetrem hledat místo, kde chybí napětí... Za pár vteřin zjištěno, že napětí není nikde. Tedy už transformátor nedává ani kapku.

Transformátor je v tahu. Primární vinutí má nekonečný odpor, asi je přetavené.

Rád bych ověřil, zda trafo s sebou do věčných lovišť nevzalo i eletroniku. Bohužel nejsem vybaven regulovatelným zdrojem. Podle štítku dává nabíječka na výstupu 18V stejnosměr. Na plošném spoji chybí výkonnový prvek či vysokonapěťové součástky, tipuji že na vstupu elektroniky bude přibližně také 18V.

Pokus: Vytahuju nabíječku na autobaterii - dává 12V a to by mohlo pro ověření stačit. Po zapojení autonabíječky na vstupní můstek se rozsvítí mně známá, zelená kontrolka. Přiložím akumulátor a zkusím stisknout tlačítko k nabití. Relátko začne cvakat spolu s blikáním červené kontrolky - tedy nabíjení... super, zdá se, že vše maká. Jen 12V je dost málo na stabilní nabíjení.

Rozebrání transformátoru

Opět se přesvědčuji, že všechny (low-cost) výrobky nejsou určeny k tomu, aby se je kdokoli pokoušel opravit. Plechy transformátoru jsou totiž zality v laku a vypadá to, že není v lidských silách trafo vůbec rozebrat. Připravím si správné náčiní a pokouším se porušit fyzikální a ekonomické zákony.


Plech není možné vyndat bez požkození. Nemaje, co ztratit, rvu to co se dá... Asi po deseti minutách je totálně zdevastovaný plech konečně venku.


První plech je zničen. Další dva tři plechy jsou o něco lépe a po vyndádní nejsou tolik zohýbané. Pak se konečně vše zrychlí a plechy jdou ven zcela bez požkození.



Konečně je trafo rozebrané, jádro s vinutími je vysvobozeno.

Tepelná pojistka

Obe vinutí jsou pokryty izolační páskou. Snažím se jí odstranit z primárního vinutí - a ejhle - narazím na podivnou součástku.




Po bližším zkoumání a googlení zjištuji, že se jedná o tepelnou pojistku. K mé smůle jde o pojistu jedorázovou. Tedy po dosažení cca 130 stupňů dojde k přetavení a můžete celou akuvrtačku vyhodit. Tipuji, že problémem je právě přetavení této kamikadze součástky, vyřazuji ji z obvodu a zkouším odpor vinutí. Vinutí již není přerušeno.

Rád bych ještě na zkoušku celé trafo na stole zprovoznil. Beru většinu plechů trafa a nahrubo je naskládám přes jádro a stáhnu izolačkou, aby se trafo nerozpadlo. Ještě připojím kabel od zásuvky a trafo vyzkouším.


Po zapojení do zásukvy začne trafo dost vrčet. Je to těmi povolenými plechy jen tak staženými izolačkou. Nicméně na sekundárním vinutí máme krásných střídavých 23V.


Koupit či nekoupit

Koukám do ceníku jednoho elektro obchodu a vše je jasné: jednorázová pojistka stojí cca 15 korun, vratná asi 150kč. Chvilku váhám, zda objednat nějakou pojistku a platit poštovné či co ale pak si říkám, že trafo zapojím bez ní. Sice to nedělám s čistým svědomím, ale risknu to a budu počítat, že musím nabíjet na větraném místě z dosahu hořlavých předmětů a hlavně nepřetěžovat.

Doplnění: Rozhodně tímto nedoporučuji odstranění jakýchkoliv pojistek, tepelných nevyjímaje. Nabíječka mi odešla, když jsem intenzivně nabíjel v horku a tato low-cost nabíječka na to není nejspíš stavěna.

Opětovné sestavení transformátoru

Složit trafo je mnohem jednodušší, než ho rozebrat. Dokonce se mi povedlo dostat všechny plechy do jádra. Tedy poslední dva s použitím kladiva. Zbyl jen ten totálně požkozený plech.




Když je trafo v celku, uvažuji, zda by nebylo vhodné plechy zamáznout nějakým lakem nebo barvou, aby se samy nerozlezly nebo nevrčely. Vzhledem k tomu, že trafo po zapojení téměř nevrčí ani v provozu,v krabice je celkem na těsno a plechy celkem drží samy od sebe, nakonec nic nelakuji. Ješte zbývá vše vyzkoušet.


Frčí jak po másle.

Závěr

I dnes je možné v domácích podmínkách ledacos opravit. Mám rád, když staré věci stále slouží. To, bohužel, není filozofie dneška. Ekonomika si žádá, aby se staré či mírně požkozené vyhodilo a koupil se novější a lepší model. A to je vidět i na způsobu výroby, kde se výrobce snaží věci dělat neopravitelné, nerozebiratelné a všemožně zatavené. Škoda pro kutily, škoda pro ekologii.





úterý 2. února 2016

Oracle DB - tablespace (de)fragmentation tutorial

This article describes how the objects are "physically" stored in Oracle DB. In tutorial is used on VM with preinstalled Oracle DB 12c.

Introduction - datafile structure

Every tablespace is one or group of multiple datafiles. Datafile has 3 levels of configuration
  • File sizing - file size on hard disk, increasing size and max size.
  • Extent management - size of extents etc. (automatic / uniform size)
  • Segment management - automatic (common) / manual (PCT_USED, FREELISTS, GROUPS ... settings is necessary)
Every extent contains blocks (usual 4KiB or 8KiB) which contain rows.
Datafile structure

Tutorial

For this tutorial, connect to db as system (sys as sysdba).

Step 1 - create tablespace with one datafile

Parameters
  • Initial size 30MiB, next 20MiB if needed, maximum of size is 100MB
  • Extent has uniform size 4MiB - it is good for tutorial. Usually use automatic extent management.
  • ASSM - automatic segment space management

define ts = TBS_TEST_DATA
--
-- Create tablespace
--
CREATE TABLESPACE "&ts."
DATAFILE '/home/oracle/test_file01.dbf' SIZE 30M AUTOEXTEND ON NEXT 20M MAXSIZE 100M
EXTENT MANAGEMENT LOCAL UNIFORM SIZE 4M
SEGMENT SPACE MANAGEMENT AUTO; --  MANUAL (PCTUSED, FREELISTS, and FREELISTS GROUPS), do not use it

Step 2 - create view TABLESPACE_MAP_VIEW

This view will be used repeately - show you content of tablespace (i.e. datafile):

create view TABLESPACE_MAP_VIEW as
SELECT   'free space' owner, '      ' OBJECT, dfs.file_id, dfs.block_id, dfs.blocks, dfs.blocks*8192/1024/1024 size_In_MB, ddf.FILE_NAME
    FROM dba_free_space dfs, DBA_DATA_FILES ddf
   WHERE dfs.tablespace_name = UPPER ('&ts.') and ddf.file_id = dfs.file_id
UNION
SELECT   SUBSTR (dext.owner, 1, 20), SUBSTR (dext.segment_name, 1, 32), dext.file_id, dext.block_id, dext.blocks, dext.blocks*8192/1024/1024 size_In_MB, ddf.FILE_NAME
    FROM dba_extents dext, DBA_DATA_FILES ddf
   WHERE dext.tablespace_name = UPPER ('&ts.') and dext.file_id = ddf.file_id
ORDER BY 3, 4;

Step 3 - create table TEST_TABLE and check the datafile

First, check tablespace map: select * from TABLESPACE_MAP_VIEW;
Result: 28MB of freespace (3584 blocks):



Now, create table with only one row but allocate initial 16MiB space:

--
-- create tmp table
--
create table TEST_TABLE tablespace TBS_TEST_DATA
storage (initial 16M NEXT 10M
        PCTINCREASE 0
        MINEXTENTS 1
        MAXEXTENTS UNLIMITED)
as
  select rownum id, ao.* from ALL_OBJECTS ao where rownum<2 ; -- 0MB dat


Check the map: select * from TABLESPACE_MAP_VIEW;


You see, there will be allocated 16MB for test table (4 extents with uniform size 4MB). But table is almost empty! Contains only one row!

Step 4 - Insert some data

First, insert cca 13MB: 

--
-- insert 13mb
--
insert into TEST_TABLE
select rownum id, ao.* from ALL_OBJECTS ao; -- 13MB dat
commit;

Check it - nothing changed because of enough space was allocated before:


 And now, insert next 7MB:

--
-- insert 7mb
--
insert into TEST_TABLE
select rownum id, ao.* from ALL_OBJECTS ao where rownum<40000 ; -- 7MB dat
commit;

Check it - rest of freespace was used and next 4MB was allocated (why only 4MB and not 10MB? - db probably rounds sizes)



Step 5 - add second table (GREAT_TABLE)

Add some another table:

--
-- great
--
create table GREAT_TABLE
tablespace TBS_TEST_DATA
storage (initial 4M NEXT 4K
          PCTINCREASE 0
          MINEXTENTS 1
          MAXEXTENTS UNLIMITED)
as
select rownum id, ao.* from ALL_OBJECTS ao; -- cca 14MB data

Check the tablespace map:
  • Datafile was extended to 48MiB (add  cca 20MiB)
  • new table needs 16MiB space


Step 6 - Create "tablespace level" fragmentation for TEST_TABLE

Insert next 7 MB into table, delete second table:

--
-- insert 7mb
--
insert into TEST_TABLE
select rownum id, ao.* from ALL_OBJECTS ao where rownum<40000 ; -- 7MB dat
commit;
-- make a hole
drop table GREAT_TABLE;

See the map:


Again insert:

insert into TEST_TABLE
select rownum id, ao.* from ALL_OBJECTS ao where rownum<40000 ; -- 7MB dat
commit;
The hole will not be filled because of "segment level fragmentation"!!!. Instead new extend will be allocated:



After delete some space...
 
-- delete "random", no space will be free
delete from TEST_TABLE where id < 60000;
commit;
...no space will be free: 


Step 7 - Defragmentation of TEST_TABLE ("tablespace level" and also "segment level" fragmentation)

Check the table block usage:

set serveroutput on;
-- fragmentation in blocks
declare
   v_unformatted_blocks number;
   v_unformatted_bytes  number;
   v_fs1_blocks         number;
   v_fs1_bytes          number;
   v_fs2_blocks         number;
   v_fs2_bytes          number;
   v_fs3_blocks         number;
   v_fs3_bytes          number;
   v_fs4_blocks         number;
   v_fs4_bytes          number;
   v_full_blocks        number;
   v_full_bytes         number;
 begin
   dbms_space.space_usage('SYS',
                          'TEST_TABLE',
                          'table',
                          v_unformatted_blocks,
                          v_unformatted_bytes,
                          v_fs1_blocks,
                          v_fs1_bytes,
                          v_fs2_blocks,
                          v_fs2_bytes,
                          v_fs3_blocks,
                          v_fs3_bytes,
                          v_fs4_blocks,
                          v_fs4_bytes,
                          v_full_blocks,
                          v_full_bytes);
   
   dbms_output.put_line('Unformatted Blocks = ' || v_unformatted_blocks);
   dbms_output.put_line('Unformatted Bytes = ' || v_unformatted_bytes);
   dbms_output.put_line('FS1 Bytes (at least 0 to 25% free space) = ' || v_fs1_bytes);
   dbms_output.put_line('FS1 Blocks(at least 0 to 25% free space) = ' || v_fs1_blocks);
   dbms_output.put_line('FS2 Bytes (at least 25 to 50% free space)= ' || v_fs2_bytes);
   dbms_output.put_line('FS2 Blocks(at least 25 to 50% free space)= ' || v_fs2_blocks);
   dbms_output.put_line('FS3 Bytes (at least 50 to 75% free space) = ' || v_fs3_bytes);
   dbms_output.put_line('FS3 Blocks(at least 50 to 75% free space) = ' || v_fs3_blocks);
   dbms_output.put_line('FS4 Bytes (at least 75 to 100% free space) = ' || v_fs4_bytes);
   dbms_output.put_line('FS4 Blocks(at least 75 to 100% free space)= ' || v_fs4_blocks);
   dbms_output.put_line('Full Blocks in segment = ' || v_full_blocks);
   dbms_output.put_line('Full Bytes in segment  = ' || v_full_bytes);
 end;
Many blocks are fragmented:


Shrinking table makes some data free:
--
-- "release free space" - shrink
--
alter table TEST_TABLE enable row movement;
alter table TEST_TABLE shrink space;
Alter table TEST_TABLE shrink space cascade;
alter table TEST_TABLE disable row movement;
 -- deallocate unused extents
ALTER TABLE TEST_TABLE DEALLOCATE UNUSED;

Table is almost defragmented (one block is 50% to 75%)

See the map:

 
Defragmentation by move storage. Init 16MiB for new extents:

-- "free space" - move to new extents
--
alter table TEST_TABLE move
storage (initial 16M NEXT 10M
          PCTINCREASE 0
          MINEXTENTS 1
          MAXEXTENTS UNLIMITED);
Result of block usages:

 Move storage contains init size (in this case 16MB), therefore 4 extents are allocated. And also first 8MB are free because there was the table stored before move:

"Move storage" benefits:
  • choose some parameters similar to table creation (init size etc...)
  • better "block level" defragmentation
  • should be fast 
"shrink" benefits:
  • less capacity (does not create new extends)
  • in some cases better "extent level" defragmentation

Step 8 - cleanup

--
-- DROP
--
drop table TEST_TABLE;
drop table GREAT_TABLE;
DROP TABLESPACE "&ts." INCLUDING CONTENTS AND DATAFILES;

neděle 31. ledna 2016

Spring and OSGi

OSGi

We are using OSGi framework for ensuring dynamic modularity in our solution. OSGi is great tool for this purposes. Adding and replacing bundles (let's say plugins or jars) into running system works well. Also dependecy resolving for keep all stuff in consistent state makes us happy.

Simple OSGi runtime schema

OSGi is focused on "low-level" modularity (jars, classloaders, class dependecies and their versions, import/export classes, services...). For "high-level" modularity or, better to say "business-level" features like the Inversion of Control, you need add support from outside.

Spring 

Spring is great IoC container (and even more) for creating apps. It is well known, popular and extensible. Huge community ensures support, project is very active and still inovative. Therefore would like to add Spring as IoC to our OSGi based system.

Simple Spring IoC container runtime schema

IoC and OSGi

Spring developers tried to break through OSGi world with "Spring Dynamic Modules". Unfortunately this project is almost dead. As a replacement is recommended to use an OSGi extension called "Blueprint", which is specification of IoC for OSGi framework. There are two usable implementations:
  • Eclipse Gemini Blueprint
  • Apache Aries Bluperint
... but, they are not Spring:(

Only one think which was done (by Apache ServiceMix community) is Spring framework wrapped as bundles. It was a starting point for our integration.

Our simple solution for Spring-OSGi

Our solution works very simple way which is sufficient for almost usecases:
  • Every OSGi-bundle has it's own isolated application context
  • Application context is defined by java configuration only.
  • Public and listen to service with cardinality 1..1.
  • No service filtering.
Our solution Spring-OSGi

Annotations

We need to define annotations which define spring beans as public services and also external beans which are imported via services into context (from outside).

Annotation for public spring beans into OSGi world as a OSGi service:

  @Retention(RetentionPolicy.RUNTIME)
  public @interface ExposeAsService  {}

Annotation for obtain OSGi service into spring world:

  @Retention(RetentionPolicy.RUNTIME)
  public @interface ObtainAsService {}
 
Example of application context configuration via java class:

@Configuration 
public abstract class DatabaseServicesContextConfiguration {
  @Bean
  @ExposeAsService
  protected ISystemService systemService() {
    return new SystemService();
  }
  
  @Bean
  @ObtainAsService
  public abstract IAppPropertiesService appProperties();
}

New post-processor and application-context

We need "somehow" handle new declared annotations. Therefore bean-factory-post-processor and application context will be created.

OsgiServiceObtainerBeanFactoryPostProcessor
This bean-factory-post-processor uses simple "trick": find all bean-definitions in context annotated by @ObtainAsService. Those definitions are removed and replaced by singleton instance of class which was lookuped from OSGi as service.

public class OsgiServiceObtainerBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
     private final BundleContext bundleContext;


     public
OsgiServiceObtainerBeanFactoryPostProcessor(BundleContext bundleContext) {
         this.bundleContext = bundleContext;
      }
         /** 

          * Find beanDefinitios with annotation ObtainAsService, 
          * lookup this service and register this service as

     * singletons into spring context. 
     */ 
      @Override    
      public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        
        DefaultListableBeanFactory beanFactoryEx = ((DefaultListableBeanFactory)beanFactory);

        // all beanDefinitions 
        String[] beanDefinitionNames = beanFactoryEx.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
           BeanDefinition beanDefinition = beanFactoryEx.getBeanDefinition(beanDefinitionName);
           if (beanDefinition.getSource() instanceof StandardMethodMetadata) {
              StandardMethodMetadata metadata = (StandardMethodMetadata)(beanDefinition.getSource()); 
              if (metadata.isAnnotated(ObtainAsService.class.getCanonicalName())) {            
               
               // 1. remove abstract definition 
               beanFactoryEx.removeBeanDefinition(beanDefinitionName); 
               
               // 2. get service from osgi
               String serviceClassName = metadata.getIntrospectedMethod().getReturnType().getCanonicalName();
               serviceInstance = getServiceTracker(serviceClassName).waitForService(0);
               ...   
               
               // 3. register service as singleton
               ...                
               beanFactoryEx.registerSingleton(metadata.getMethodName(), serviceInstance);
               ...
             }
         }
      }
   }
   ...
}

OsgiApplicationContext
This context is used in bundle activator and adds support for OSGi via "BundleContext" instance which is obrained in constructor. In constructor is also added "osgi bean-postprocessor" for service obtaining. Method "exposeService" ensures publicing annotated services into OSGi.

public class OsgiApplicationContext extends AnnotationConfigApplicationContext {

  private BundleContext bundleContext;

  // all exposed services.
  private List<ServiceRegistration> serviceRegistrations = new ArrayList<ServiceRegistration>();

  public OsgiApplicationContext(BundleContext bundleContext) {
    if (bundleContext!=null) {
      this.addBeanFactoryPostProcessor(new OsgiServiceObtainerBeanFactoryPostProcessor(bundleContext));
      this.bundleContext = bundleContext;
    } 
  }
  
  /**
   * Expose beans annotated as "ExposeAsService" to OSGi as services 
   */
  public void exposeServices() {
   // get beanDefinition of current bean
   for (String name : this.getBeanDefinitionNames()) {
      BeanDefinition beanDefinition = this.getBeanDefinition(name);
      if (beanDefinition.getSource() instanceof StandardMethodMetadata) {
         StandardMethodMetadata metadata = (StandardMethodMetadata)(beanDefinition.getSource()); 
         if (metadata.isAnnotated(ExposeAsService.class.getCanonicalName())) {
            String className = metadata.getIntrospectedMethod().getReturnType().getCanonicalName();
            // expose as service
            Object bean = this.getBean(name);
            LOGGER.info("Exposing bean "+name+" "+bean.toString() + " as a service "+className);
            ServiceRegistration serviceRegistration = this.bundleContext.registerService(className, bean, null);
            this.serviceRegistrations.add(serviceRegistration);
         }
      }
    }
  }
  @Override
  public void close() {
   for (ServiceRegistration registration : this.serviceRegistrations) {
      registration.unregister();
   }
   super.close();
  } 
} 


Bundle activator example

Usage of these classes is quite simple:
public class DatabaseServiceActivator implements BundleActivator {
  @Override
  public void start(final BundleContext bundleContext) throws Exception {
    springContext = new OsgiApplicationContext(bundleContext);
    springContext.setClassLoader(this.getClass().getClassLoader());
    springContext.register(DatabaseServicesContextConfiguration.class); 
    springContext.refresh();  
    springContext.exposeServices();
  } 
}

When bundle is activated, spring context will be created and obtains some beans as services from outside. After context activation (refresh call), some beans will be exposed as services. Important is to set classloader, because spring runs under it's own classloader and he cannot see your bean classes.

Future

Great news are comming from Apache Aries community! Blueprint will be implemented as "bridge" for Spring IoC. First release 0.1.0 is on download page at Apache Aries web.

When it will be more stable, we can replace our simple solution with more featured implementation.

http://aries.apache.org/modules/blueprint.html